Merge "Add CEPHFS filesystem metadata verifications"
diff --git a/doc/source/conf.py b/doc/source/conf.py
old mode 100755
new mode 100644
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index aebf4a9..4afa4e7 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -40,7 +40,7 @@
                     "This value is only used to validate the versions "
                     "response from Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="2.85",
+               default="2.88",
                help="The maximum api microversion is configured to be the "
                     "value of the latest microversion supported by Manila."),
     cfg.StrOpt("region",
@@ -108,6 +108,12 @@
     cfg.ListOpt("enable_ro_access_level_for_protocols",
                 default=["nfs", ],
                 help="List of protocols to run tests with ro access level."),
+    cfg.ListOpt("nfs_versions",
+                default=["4", ],
+                help="Specifies the NFS protocol version to use when mounting "
+                     "an NFS share. Set to '3' for NFSv3, and '4' or '4.1' "
+                     "for NFSv4. Leave it blank to use the default version."),
+
 
     # Capabilities
     cfg.StrOpt("capability_storage_protocol",
@@ -308,6 +314,7 @@
                default="manila",
                help="Image username."),
     cfg.StrOpt("image_password",
+               secret=True,
                help="Image password. Should be used for "
                     "'image_with_share_tools' without Nova Metadata support."),
     cfg.StrOpt("client_vm_flavor_ref",
@@ -322,7 +329,7 @@
                help="Time to wait for share backup before "
                     "timing out (seconds)."),
     cfg.IntOpt("share_server_migration_timeout",
-               default="1500",
+               default=1500,
                help="Time to wait for share server migration before "
                     "timing out (seconds)."),
     cfg.StrOpt("default_share_type_name",
@@ -334,6 +341,18 @@
     cfg.IntOpt("share_size",
                default=1,
                help="Default size in GB for shares created by share tests."),
+    cfg.IntOpt("additional_overflow_blocks",
+               default=0,
+               help="Additional blocks to be written "
+                    "to share in scenario tests."),
+    cfg.IntOpt("share_resize_sync_delay",
+               default=0,
+               help="Time to wait before the changes to the share size"
+                    " are propagated to the storage system."),
+    cfg.IntOpt("share_growth_size",
+               default=1,
+               help="The default increase in size sought by tests"
+                    " when validating share resizing within scenario tests."),
     cfg.BoolOpt("run_ipv6_tests",
                 default=False,
                 help="Enable or disable running IPv6 NFS scenario tests. "
diff --git a/manila_tempest_tests/services/share/json/shares_client.py b/manila_tempest_tests/services/share/json/shares_client.py
index fb03afc..63a634c 100644
--- a/manila_tempest_tests/services/share/json/shares_client.py
+++ b/manila_tempest_tests/services/share/json/shares_client.py
@@ -304,37 +304,41 @@
                 return True
             else:
                 return self._is_resource_deleted(
-                    self.get_share, kwargs.get("share_id"))
+                    self.get_share, kwargs.get("share_id"), "share")
         elif "snapshot_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_snapshot, kwargs.get("snapshot_id"))
+                self.get_snapshot, kwargs.get("snapshot_id"), "snapshot")
         elif "sn_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_share_network, kwargs.get("sn_id"))
+                self.get_share_network, kwargs.get("sn_id"), "share_network")
         elif "ss_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_security_service, kwargs.get("ss_id"))
+                self.get_security_service, kwargs.get("ss_id"),
+                "security_service")
         elif "vt_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_volume_type, kwargs.get("vt_id"))
+                self.get_volume_type, kwargs.get("vt_id"), "volume_type")
         elif "st_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_share_type, kwargs.get("st_id"))
+                self.get_share_type, kwargs.get("st_id"), "share_type")
         elif "server_id" in kwargs:
             return self._is_resource_deleted(
-                self.show_share_server, kwargs.get("server_id"))
+                self.show_share_server, kwargs.get("server_id"),
+                "share_server")
         elif "backup_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_share_backup, kwargs.get("backup_id"))
+                self.get_share_backup, kwargs.get("backup_id"),
+                "share_backup")
         else:
             raise share_exceptions.InvalidResource(
                 message=str(kwargs))
 
-    def _is_resource_deleted(self, func, res_id, **kwargs):
+    def _is_resource_deleted(self, func, res_id, resource_name, **kwargs):
         try:
-            res = func(res_id, **kwargs)
+            res = func(res_id, **kwargs)[resource_name]
         except exceptions.NotFound:
             return True
+
         if res.get('status') in ['error_deleting', 'error']:
             # Resource has "error_deleting" status and can not be deleted.
             resource_type = func.__name__.split('_', 1)[-1]
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
index e3a022e..a9ab199 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -208,29 +208,33 @@
         """
         if "share_instance_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_share_instance, kwargs.get("share_instance_id"))
+                self.get_share_instance, kwargs.get("share_instance_id"),
+                "share_instance")
         elif "share_group_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_share_group, kwargs.get("share_group_id"))
+                self.get_share_group, kwargs.get("share_group_id"),
+                "share_group")
         elif "share_group_snapshot_id" in kwargs:
             return self._is_resource_deleted(
                 self.get_share_group_snapshot,
-                kwargs.get("share_group_snapshot_id"))
+                kwargs.get("share_group_snapshot_id"), "share_group_snapshot")
         elif "share_group_type_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_share_group_type, kwargs.get("share_group_type_id"))
+                self.get_share_group_type, kwargs.get("share_group_type_id"),
+                "share_group_type")
         elif "replica_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_share_replica, kwargs.get("replica_id"))
+                self.get_share_replica, kwargs.get("replica_id"),
+                "share_replica")
         elif "message_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_message, kwargs.get("message_id"))
+                self.get_message, kwargs.get("message_id"), "message")
         elif "share_network_subnet_id" in kwargs:
             subnet_kwargs = {
-                "sn_id": kwargs["extra_params"]["share_network_id"]}
+                "share_network_id": kwargs["sn_id"]}
             return self._is_resource_deleted(
                 self.get_subnet, kwargs.get("share_network_subnet_id"),
-                **subnet_kwargs
+                "share_network_subnet", **subnet_kwargs
             )
         else:
             return super(SharesV2Client, self).is_resource_deleted(
@@ -899,6 +903,15 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
+    def update_access_rule(self, access_id, access_level,
+                           version=LATEST_MICROVERSION):
+        url = 'share-access-rules/%s' % access_id
+        body = {'update_access': {"access_level": access_level}}
+        resp, body = self.put(url, json.dumps(body), version=version)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
     def update_access_metadata(self, access_id, metadata,
                                version=LATEST_MICROVERSION):
         url = 'share-access-rules/%s/metadata' % access_id
diff --git a/manila_tempest_tests/tests/api/admin/test_export_locations.py b/manila_tempest_tests/tests/api/admin/test_export_locations.py
index db382f2..74df8d1 100644
--- a/manila_tempest_tests/tests/api/admin/test_export_locations.py
+++ b/manila_tempest_tests/tests/api/admin/test_export_locations.py
@@ -58,6 +58,8 @@
         summary_keys = ['id', 'path']
         if utils.is_microversion_ge(version, '2.14'):
             summary_keys += ['preferred']
+        if utils.is_microversion_ge(version, '2.87'):
+            summary_keys += ['metadata']
 
         admin_summary_keys = summary_keys + [
             'share_instance_id', 'is_admin_only']
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py b/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py
index c850f66..c6f3549 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py
@@ -342,39 +342,6 @@
             dest_host
         )
 
-    @decorators.idempotent_id('ebe8da5b-ee9c-48c7-a7e4-9e71839f813f')
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_share_server_migration_start_with_share_replica(self):
-        """Try server migration start with share replica."""
-        if not CONF.share.backend_replication_type or (
-                not CONF.share.run_replication_tests):
-            raise self.skipException(
-                'Share replica tests are disabled or unsupported.')
-        extra_specs = {
-            'driver_handles_share_servers': CONF.share.multitenancy_enabled,
-            'replication_type': CONF.share.backend_replication_type
-        }
-        share_type = self.shares_v2_client.create_share_type(
-            name=data_utils.rand_name("tempest-share-type"),
-            extra_specs=extra_specs,
-            cleanup_in_class=False)
-        share = self.create_share(share_type_id=share_type['share_type']['id'],
-                                  share_protocol=self.protocol,
-                                  cleanup_in_class=False)
-        share = self.shares_v2_client.get_share(share['id'])['share']
-        share_server_id = share['share_server_id']
-        dest_host, _ = self._choose_compatible_backend_for_share_server(
-            share_server_id)
-        self.create_share_replica(
-            share['id'],
-            cleanup_in_class=False)
-        self.assertRaises(
-            lib_exc.Conflict,
-            self.shares_v2_client.share_server_migration_start,
-            share_server_id,
-            dest_host
-        )
-
 
 class ShareServerMigrationInvalidParametersCIFS(
     ShareServerMigrationInvalidParametersNFS):
diff --git a/manila_tempest_tests/tests/api/admin/test_shares_actions.py b/manila_tempest_tests/tests/api/admin/test_shares_actions.py
index 29c7e04..7ad6b1e 100644
--- a/manila_tempest_tests/tests/api/admin/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/admin/test_shares_actions.py
@@ -164,8 +164,8 @@
         # verify response
         self.assertGreater(len(shares), 0)
         for share in shares:
-            self.assertDictContainsSubset(
-                filters['metadata'], share['metadata'])
+            self.assertLessEqual(filters['metadata'].items(),
+                                 share['metadata'].items())
         if CONF.share.capability_create_share_from_snapshot_support:
             self.assertFalse(self.shares[1]['id'] in [s['id'] for s in shares])
 
@@ -203,7 +203,8 @@
                 )
             extra_specs = self.shares_client.get_share_type_extra_specs(
                 st_id)['extra_specs']
-            self.assertDictContainsSubset(filters["extra_specs"], extra_specs)
+            self.assertLessEqual(filters["extra_specs"].items(),
+                                 extra_specs.items())
 
     @decorators.idempotent_id('76fbe8ba-f1d3-4446-b9b8-55617762a2c7')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
old mode 100755
new mode 100644
index 2db2353..9583de8
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -898,69 +898,80 @@
                 res["deleted"] = False
             if "client" not in res.keys():
                 res["client"] = cls.shares_client
-            if not(res["deleted"]):
-                res_id = res['id']
-                client = res["client"]
-                with handle_cleanup_exceptions():
-                    if res["type"] == "share":
-                        cls.clear_share_replicas(res_id)
-                        share_group_id = res.get('share_group_id')
-                        if share_group_id:
-                            params = {'share_group_id': share_group_id}
-                            client.delete_share(res_id, params=params)
+            if not (res["deleted"]):
+                try:
+                    res_id = res['id']
+                    client = res["client"]
+                    with handle_cleanup_exceptions():
+                        if res["type"] == "share":
+                            cls.clear_share_replicas(res_id)
+                            share_group_id = res.get('share_group_id')
+                            if share_group_id:
+                                params = {'share_group_id': share_group_id}
+                                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"] == "snapshot":
+                            client.delete_snapshot(res_id)
+                            client.wait_for_resource_deletion(
+                                snapshot_id=res_id)
+                        elif (res["type"] == "share_network" and
+                                res_id != CONF.share.share_network_id):
+                            client.delete_share_network(res_id)
+                            client.wait_for_resource_deletion(sn_id=res_id)
+                        elif res["type"] == "dissociate_security_service":
+                            sn_id = res["extra_params"]["share_network_id"]
+                            client.remove_sec_service_from_share_network(
+                                sn_id=sn_id, ss_id=res_id
+                            )
+                        elif res["type"] == "security_service":
+                            client.delete_security_service(res_id)
+                            client.wait_for_resource_deletion(ss_id=res_id)
+                        elif res["type"] == "share_type":
+                            client.delete_share_type(res_id)
+                            client.wait_for_resource_deletion(st_id=res_id)
+                        elif res["type"] == "share_group":
+                            client.delete_share_group(res_id)
+                            client.wait_for_resource_deletion(
+                                share_group_id=res_id)
+                        elif res["type"] == "share_group_type":
+                            client.delete_share_group_type(res_id)
+                            client.wait_for_resource_deletion(
+                                share_group_type_id=res_id)
+                        elif res["type"] == "share_group_snapshot":
+                            client.delete_share_group_snapshot(res_id)
+                            client.wait_for_resource_deletion(
+                                share_group_snapshot_id=res_id)
+                        elif res["type"] == "share_replica":
+                            client.delete_share_replica(res_id)
+                            client.wait_for_resource_deletion(
+                                replica_id=res_id)
+                        elif res["type"] == "share_backup":
+                            client.delete_share_backup(res_id)
+                            client.wait_for_resource_deletion(backup_id=res_id)
+                        elif res["type"] == "share_network_subnet":
+                            sn_id = res["extra_params"]["share_network_id"]
+                            client.delete_subnet(sn_id, res_id)
+                            client.wait_for_resource_deletion(
+                                share_network_subnet_id=res_id,
+                                sn_id=sn_id)
+                        elif res["type"] == "quotas":
+                            user_id = res.get('user_id')
+                            client.reset_quotas(res_id, user_id=user_id)
+                        elif res["type"] == "resource_lock":
+                            client.delete_resource_lock(res_id)
                         else:
-                            client.delete_share(res_id)
-                        client.wait_for_resource_deletion(share_id=res_id)
-                    elif res["type"] == "snapshot":
-                        client.delete_snapshot(res_id)
-                        client.wait_for_resource_deletion(snapshot_id=res_id)
-                    elif (res["type"] == "share_network" and
-                            res_id != CONF.share.share_network_id):
-                        client.delete_share_network(res_id)
-                        client.wait_for_resource_deletion(sn_id=res_id)
-                    elif res["type"] == "dissociate_security_service":
-                        sn_id = res["extra_params"]["share_network_id"]
-                        client.remove_sec_service_from_share_network(
-                            sn_id=sn_id, ss_id=res_id
-                        )
-                    elif res["type"] == "security_service":
-                        client.delete_security_service(res_id)
-                        client.wait_for_resource_deletion(ss_id=res_id)
-                    elif res["type"] == "share_type":
-                        client.delete_share_type(res_id)
-                        client.wait_for_resource_deletion(st_id=res_id)
-                    elif res["type"] == "share_group":
-                        client.delete_share_group(res_id)
-                        client.wait_for_resource_deletion(
-                            share_group_id=res_id)
-                    elif res["type"] == "share_group_type":
-                        client.delete_share_group_type(res_id)
-                        client.wait_for_resource_deletion(
-                            share_group_type_id=res_id)
-                    elif res["type"] == "share_group_snapshot":
-                        client.delete_share_group_snapshot(res_id)
-                        client.wait_for_resource_deletion(
-                            share_group_snapshot_id=res_id)
-                    elif res["type"] == "share_replica":
-                        client.delete_share_replica(res_id)
-                        client.wait_for_resource_deletion(replica_id=res_id)
-                    elif res["type"] == "share_backup":
-                        client.delete_share_backup(res_id)
-                        client.wait_for_resource_deletion(backup_id=res_id)
-                    elif res["type"] == "share_network_subnet":
-                        sn_id = res["extra_params"]["share_network_id"]
-                        client.delete_subnet(sn_id, res_id)
-                        client.wait_for_resource_deletion(
-                            share_network_subnet_id=res_id,
-                            sn_id=sn_id)
-                    elif res["type"] == "quotas":
-                        user_id = res.get('user_id')
-                        client.reset_quotas(res_id, user_id=user_id)
-                    elif res["type"] == "resource_lock":
-                        client.delete_resource_lock(res_id)
-                    else:
-                        LOG.warning("Provided unsupported resource type for "
-                                    "cleanup '%s'. Skipping.", res["type"])
+                            LOG.warning("Provided unsupported resource type "
+                                        "for cleanup '%s'. Skipping.",
+                                        res["type"])
+                except share_exceptions.ResourceReleaseFailed as e:
+                    # Resource is on error deleting state, so we remove it from
+                    # the list to delete, since it cannot be deleted anymore.
+                    # It raises because the current cleanup class or method
+                    # must fail.
+                    res["deleted"] = True
+                    raise e
                 res["deleted"] = True
 
     # Useful assertions
@@ -1283,12 +1294,18 @@
         cls.admin_project = cls.os_admin.auth_provider.auth_data[1]['project']
         identity_clients = getattr(
             cls.os_admin, 'identity_%s' % CONF.identity.auth_version)
-        cls.os_admin.identity_client = identity_clients.IdentityClient()
-        cls.os_admin.projects_client = identity_clients.ProjectsClient()
-        cls.os_admin.users_client = identity_clients.UsersClient()
-        cls.os_admin.roles_client = identity_clients.RolesClient()
+        endpoint_type = CONF.share.endpoint_type
+        cls.os_admin.identity_client = identity_clients.IdentityClient(
+            endpoint_type=endpoint_type)
+        cls.os_admin.projects_client = identity_clients.ProjectsClient(
+            endpoint_type=endpoint_type)
+        cls.os_admin.users_client = identity_clients.UsersClient(
+            endpoint_type=endpoint_type)
+        cls.os_admin.roles_client = identity_clients.RolesClient(
+            endpoint_type=endpoint_type)
         cls.os_admin.domains_client = (
-            cls.os_admin.identity_v3.DomainsClient() if
+            cls.os_admin.identity_v3.DomainsClient(
+                endpoint_type=endpoint_type) if
             CONF.identity.auth_version == 'v3' else None)
         cls.admin_project_member_client = cls.create_user_and_get_client(
             project=cls.admin_project, add_member_role=True)
diff --git a/manila_tempest_tests/tests/api/test_access_rules_metadata_negative.py b/manila_tempest_tests/tests/api/test_access_rules_metadata_negative.py
index 98a1361..c212095 100644
--- a/manila_tempest_tests/tests/api/test_access_rules_metadata_negative.py
+++ b/manila_tempest_tests/tests/api/test_access_rules_metadata_negative.py
@@ -20,6 +20,7 @@
 from testtools import testcase as tc
 
 from manila_tempest_tests.common import constants
+from manila_tempest_tests.common import waiters
 from manila_tempest_tests.tests.api import base
 from manila_tempest_tests import utils
 
@@ -67,6 +68,9 @@
         cls.access = cls.shares_v2_client.create_access_rule(
             cls.share["id"], cls.access_type, cls.access_to,
             'rw', metadata={u"key1": u"value1"})['access']
+        waiters.wait_for_resource_status(
+            cls.shares_v2_client, cls.share["id"], "active",
+            resource_name='access_rule', rule_id=cls.access["id"])
 
     @decorators.idempotent_id('d2d41db8-ae00-4641-a5ec-499cee1877f1')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
diff --git a/manila_tempest_tests/tests/api/test_replication_export_locations.py b/manila_tempest_tests/tests/api/test_replication_export_locations.py
index 2227290..bff8d2d 100644
--- a/manila_tempest_tests/tests/api/test_replication_export_locations.py
+++ b/manila_tempest_tests/tests/api/test_replication_export_locations.py
@@ -196,6 +196,9 @@
         """Validates exports from the replica export locations APIs"""
         el_summary_keys = ['id', 'path', 'replica_state',
                            'availability_zone', 'preferred']
+        if utils.is_microversion_ge(LATEST_MICROVERSION, '2.87'):
+            el_summary_keys += ['metadata']
+
         el_detail_keys = el_summary_keys + ['created_at', 'updated_at']
         share, replica, expected_primary_exports, expected_replica_exports = (
             self._create_share_and_replica_get_exports()
diff --git a/manila_tempest_tests/tests/api/test_rules.py b/manila_tempest_tests/tests/api/test_rules.py
index 5f39852..99ac254 100644
--- a/manila_tempest_tests/tests/api/test_rules.py
+++ b/manila_tempest_tests/tests/api/test_rules.py
@@ -22,6 +22,7 @@
 import testtools
 from testtools import testcase as tc
 
+from manila_tempest_tests.common import waiters
 from manila_tempest_tests.tests.api import base
 from manila_tempest_tests import utils
 
@@ -62,6 +63,7 @@
             self.share['id'])['access_list']
         rule = [r for r in rules if r['id'] == rule['id']][0]
         self.assertEqual("active", rule['state'])
+    return rule
 
 
 @ddt.ddt
@@ -162,8 +164,23 @@
         "RO access rule tests are disabled for NFS protocol.")
     @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
                                  LATEST_MICROVERSION]))
-    def test_create_delete_ro_access_rule(self, client_name):
-        _create_delete_ro_access_rule(self, client_name)
+    def test_create_delete_ro_access_rule(self, version):
+        _create_delete_ro_access_rule(self, version)
+
+    @utils.skip_if_microversion_not_supported('2.88')
+    @decorators.idempotent_id('01940881-6f95-77f8-b47d-0941c4e6bafb')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    @testtools.skipIf(
+        "nfs" not in CONF.share.enable_ro_access_level_for_protocols,
+        "RO access rule tests are disabled for NFS protocol.")
+    def test_update_access_rule(self):
+        rule = _create_delete_ro_access_rule(self, LATEST_MICROVERSION)
+        rule = self.shares_v2_client.update_access_rule(
+            access_id=rule['id'], access_level='rw')['access']
+        waiters.wait_for_resource_status(
+            self.shares_v2_client, self.share['id'], status='active',
+            resource_name='access_rule', rule_id=rule['id'])
+        self.assertEqual(rule['access_level'], 'rw')
 
 
 @ddt.ddt
@@ -180,6 +197,18 @@
     def test_create_delete_ro_access_rule(self, version):
         _create_delete_ro_access_rule(self, version)
 
+    @utils.skip_if_microversion_not_supported('2.88')
+    @decorators.idempotent_id('02940881-6f95-77f8-b47d-0941c4e6bafb')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    @testtools.skipIf(
+        "cifs" not in CONF.share.enable_ro_access_level_for_protocols,
+        "RO access rule tests are disabled for CIFS protocol.")
+    def test_update_access_rule(self):
+        super(
+            ShareIpRulesForCIFSTest,
+            self
+        ).test_update_access_rule()
+
 
 @ddt.ddt
 class ShareUserRulesForNFSTest(base.BaseSharesMixedTest):
diff --git a/manila_tempest_tests/tests/api/test_rules_negative.py b/manila_tempest_tests/tests/api/test_rules_negative.py
index 32c4e9f..0757c8e 100644
--- a/manila_tempest_tests/tests/api/test_rules_negative.py
+++ b/manila_tempest_tests/tests/api/test_rules_negative.py
@@ -368,6 +368,27 @@
                           CONF.share.username_for_user_rules,
                           'su')
 
+    @utils.skip_if_microversion_not_supported('2.88')
+    @decorators.idempotent_id('d5b1e7c9-7e6b-4918-a1c4-e03c8d82c46a')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_access_rule_with_wrong_level(self):
+        access_type, access_to = utils.get_access_rule_data_from_config(
+            self.protocol)
+        if access_type != 'ip':
+            msg = "Access rule updates supported only for 'ip' access."
+            raise self.skipException(msg)
+
+        rule = self.allow_access(
+            self.share["id"], client=self.shares_v2_client,
+            access_type=access_type, access_to=access_to)
+
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.shares_v2_client.update_access_rule,
+            rule['id'],
+            access_level='fake_level'
+        )
+
 
 @ddt.ddt
 class ShareUserRulesForCIFSNegativeTest(ShareUserRulesForNFSNegativeTest):
@@ -499,22 +520,24 @@
     @decorators.idempotent_id('4ffed391-d7cc-481b-bb74-9f3406ddd75f')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_different_tenants_cannot_use_same_cephx_id(self):
+        scheduler_hint = {"same_host": "%s" % self.share["id"]}
+
         # Grant access to the share
         self.allow_access(self.share['id'], access_to=self.access_to)
-
         # Create second share by the new user
-        share2 = self.create_share(client=self.alt_shares_v2_client,
+        share2 = self.create_share(client=self.admin_shares_v2_client,
                                    share_protocol=self.protocol,
-                                   share_type_id=self.share_type_id)
+                                   share_type_id=self.share_type_id,
+                                   scheduler_hints=scheduler_hint)
 
         # Try grant access to the second share using the same cephx id as used
         # on the first share.
         # Rule must be set to "error" status.
-        self.allow_access(share2['id'], client=self.alt_shares_v2_client,
+        self.allow_access(share2['id'], client=self.admin_shares_v2_client,
                           access_to=self.access_to, status='error',
                           raise_rule_in_error_state=False)
 
-        share_alt_updated = self.alt_shares_v2_client.get_share(
+        share_alt_updated = self.admin_shares_v2_client.get_share(
             share2['id'])['share']
         self.assertEqual('error', share_alt_updated['access_rules_status'])
 
@@ -522,34 +545,39 @@
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_can_apply_new_cephx_rules_when_one_is_in_error_state(self):
         # Create share on "primary" tenant
-        share_primary = self.create_share()
+        share_primary = self.create_share(
+            share_type_id=self.share_type_id)
         # Add access rule to "Joe" by "primary" user
         self.allow_access(share_primary['id'], access_to='Joe')
 
-        # Create share on "alt" tenant
-        share_alt = self.create_share(client=self.alt_shares_v2_client)
-        # Add access rule to "Joe" by "alt" user.
+        scheduler_hint = {"same_host": "%s" % share_primary["id"]}
+        # Create share on "admin" tenant
+        share_adm = self.create_share(
+            client=self.admin_shares_v2_client,
+            share_type_id=self.share_type_id,
+            scheduler_hints=scheduler_hint)
+        # Add access rule to "Joe" by "admin" user.
         # Rule must be set to "error" status.
-        rule1 = self.allow_access(share_alt['id'],
-                                  client=self.alt_shares_v2_client,
+        rule1 = self.allow_access(share_adm['id'],
+                                  client=self.admin_shares_v2_client,
                                   access_to='Joe',
                                   status='error',
                                   raise_rule_in_error_state=False,
                                   cleanup=False)
 
         # Share's "access_rules_status" must be in "error" status
-        share_alt_updated = self.alt_shares_v2_client.get_share(
-            share_alt['id'])['share']
-        self.assertEqual('error', share_alt_updated['access_rules_status'])
+        share_adm_updated = self.admin_shares_v2_client.get_share(
+            share_adm['id'])['share']
+        self.assertEqual('error', share_adm_updated['access_rules_status'])
 
-        # Add second access rule to different client by "alt" user.
-        self.allow_access(share_alt['id'], client=self.alt_shares_v2_client)
+        # Add second access rule to different client by "admin" user.
+        self.allow_access(share_adm['id'], client=self.admin_shares_v2_client)
 
         # Check share's access_rules_status has transitioned to "active" status
-        self.alt_shares_v2_client.delete_access_rule(
-            share_alt['id'], rule1['id'])
+        self.admin_shares_v2_client.delete_access_rule(
+            share_adm['id'], rule1['id'])
         waiters.wait_for_resource_status(
-            self.alt_shares_v2_client, share_alt['id'], 'active',
+            self.admin_shares_v2_client, share_adm['id'], 'active',
             status_attr='access_rules_status')
 
 
diff --git a/manila_tempest_tests/tests/api/test_security_services.py b/manila_tempest_tests/tests/api/test_security_services.py
index 85ed5fb..1e34295 100644
--- a/manila_tempest_tests/tests/api/test_security_services.py
+++ b/manila_tempest_tests/tests/api/test_security_services.py
@@ -166,7 +166,7 @@
         self.service_names = ["ldap", "kerberos", "active_directory"]
         for ss_name in self.service_names:
             ss = self.create_security_service(ss_name, **data)
-            self.assertDictContainsSubset(data, ss)
+            self.assertLessEqual(data.items(), ss.items())
             self.assertEqual(ss_name, ss["type"])
             self.shares_client.delete_security_service(ss["id"])
 
@@ -188,9 +188,9 @@
             get = self.shares_client.get_security_service(
                 ss["id"])['security_service']
 
-        self.assertDictContainsSubset(data, ss)
+        self.assertLessEqual(data.items(), ss.items())
         self.assertEqual(with_ou, 'ou' in ss)
-        self.assertDictContainsSubset(data, get)
+        self.assertLessEqual(data.items(), get.items())
         self.assertEqual(with_ou, 'ou' in get)
 
     @decorators.idempotent_id('84d47747-13c8-4ab9-9fc4-a43fbb29ad18')
@@ -198,7 +198,7 @@
     def test_update_security_service(self):
         data = utils.generate_security_service_data()
         ss = self.create_security_service(**data)
-        self.assertDictContainsSubset(data, ss)
+        self.assertLessEqual(data.items(), ss.items())
 
         upd_data = utils.generate_security_service_data()
         updated = self.shares_client.update_security_service(
@@ -206,8 +206,8 @@
 
         get = self.shares_client.get_security_service(
             ss["id"])['security_service']
-        self.assertDictContainsSubset(upd_data, updated)
-        self.assertDictContainsSubset(upd_data, get)
+        self.assertLessEqual(upd_data.items(), updated.items())
+        self.assertLessEqual(upd_data.items(), get.items())
 
         if utils.is_microversion_ge(CONF.share.max_api_microversion, '2.44'):
             # update again with ou
@@ -217,8 +217,8 @@
 
             get_ou = self.shares_v2_client.get_security_service(
                 ss["id"])['security_service']
-            self.assertDictContainsSubset(upd_data_ou, updated_ou)
-            self.assertDictContainsSubset(upd_data_ou, get_ou)
+            self.assertLessEqual(upd_data_ou.items(), updated_ou.items())
+            self.assertLessEqual(upd_data_ou.items(), get_ou.items())
 
     @decorators.idempotent_id('c3c04992-da11-4677-9098-eff3f4231a4b')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -259,7 +259,7 @@
         }
         updated = self.shares_client.update_security_service(
             ss["id"], **update_data)['security_service']
-        self.assertDictContainsSubset(update_data, updated)
+        self.assertLessEqual(update_data.items(), updated.items())
 
     @decorators.idempotent_id('8d9af272-df89-470d-9ff8-92ba774c9fff')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
diff --git a/manila_tempest_tests/tests/api/test_security_services_mapping.py b/manila_tempest_tests/tests/api/test_security_services_mapping.py
index 6ce9a0a..4c2d272 100644
--- a/manila_tempest_tests/tests/api/test_security_services_mapping.py
+++ b/manila_tempest_tests/tests/api/test_security_services_mapping.py
@@ -36,13 +36,13 @@
         self.sn = self.create_share_network(client=self.cl,
                                             add_security_services=False,
                                             **data)
-        self.assertDictContainsSubset(data, self.sn)
+        self.assertLessEqual(data.items(), self.sn.items())
 
         # create security service
         data = utils.generate_security_service_data()
 
         self.ss = self.create_security_service(client=self.cl, **data)
-        self.assertDictContainsSubset(data, self.ss)
+        self.assertLessEqual(data.items(), self.ss.items())
 
         # Add security service to share network
         self.cl.add_sec_service_to_share_network(self.sn["id"], self.ss["id"])
diff --git a/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py b/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
index 96506ce..f5b06e8 100644
--- a/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
+++ b/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
@@ -150,14 +150,14 @@
 
         sn = self.create_share_network(client=self.cl,
                                        add_security_services=False, **data)
-        self.assertDictContainsSubset(data, sn)
+        self.assertLessEqual(data.items(), sn.items())
 
         # create security services with same type
         security_services = []
         for i in range(2):
             data = utils.generate_security_service_data()
             ss = self.create_security_service(client=self.cl, **data)
-            self.assertDictContainsSubset(data, ss)
+            self.assertLessEqual(data.items(), ss.items())
             security_services.insert(i, ss)
 
         # Add security service to share network
@@ -177,13 +177,13 @@
 
         sn = self.create_share_network(client=self.cl,
                                        add_security_services=False, **data)
-        self.assertDictContainsSubset(data, sn)
+        self.assertLessEqual(data.items(), sn.items())
 
         # create security service
         data = utils.generate_security_service_data()
 
         ss = self.create_security_service(client=self.cl, **data)
-        self.assertDictContainsSubset(data, ss)
+        self.assertLessEqual(data.items(), ss.items())
 
         # Add security service to share network
         self.cl.add_sec_service_to_share_network(sn["id"], ss["id"])
diff --git a/manila_tempest_tests/tests/api/test_security_services_negative.py b/manila_tempest_tests/tests/api/test_security_services_negative.py
index 23c7cc1..733247e 100644
--- a/manila_tempest_tests/tests/api/test_security_services_negative.py
+++ b/manila_tempest_tests/tests/api/test_security_services_negative.py
@@ -132,7 +132,7 @@
     def test_get_deleted_security_service(self):
         data = utils.generate_security_service_data()
         ss = self.create_security_service(**data)
-        self.assertDictContainsSubset(data, ss)
+        self.assertLessEqual(data.items(), ss.items())
 
         self.shares_client.delete_security_service(ss["id"])
 
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnets.py b/manila_tempest_tests/tests/api/test_share_network_subnets.py
index 1ae5351..09f903c 100644
--- a/manila_tempest_tests/tests/api/test_share_network_subnets.py
+++ b/manila_tempest_tests/tests/api/test_share_network_subnets.py
@@ -81,7 +81,7 @@
         # Default subnet was created during share network creation
         self.assertIsNone(default_subnet['availability_zone'])
         # Match new subnet content
-        self.assertDictContainsSubset(data, created)
+        self.assertLessEqual(data.items(), created.items())
 
         self.assertEqual(sorted(keys), sorted(list(created.keys())))
 
@@ -109,7 +109,7 @@
             created['id'], share_network['id'])['share_network_subnet']
 
         # Asserts
-        self.assertDictContainsSubset(data, shown)
+        self.assertLessEqual(data.items(), shown.items())
 
         # Deletes the created subnet
         self.shares_v2_client.delete_subnet(share_network['id'],
@@ -175,7 +175,7 @@
         # Default subnet was created during share network creation
         self.assertIsNone(default_subnet['availability_zone'])
         # Match new subnet content
-        self.assertDictContainsSubset(data, subnet)
+        self.assertLessEqual(data.items(), subnet.items())
         # Match share server subnet
         if check_multiple_subnet:
             self.assertIn(subnet['id'],
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py b/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
index 52b297e..0bb6a5c 100644
--- a/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
@@ -131,7 +131,7 @@
         subnet = self.create_share_network_subnet(**data)
 
         # Make sure that the created subnet contains the data
-        self.assertDictContainsSubset(data, subnet)
+        self.assertLessEqual(data.items(), subnet.items())
 
         # Delete the given subnet
         self.shares_v2_client.delete_subnet(self.share_network_id,
diff --git a/manila_tempest_tests/tests/api/test_share_networks.py b/manila_tempest_tests/tests/api/test_share_networks.py
index f990566..ac87fd7 100644
--- a/manila_tempest_tests/tests/api/test_share_networks.py
+++ b/manila_tempest_tests/tests/api/test_share_networks.py
@@ -224,7 +224,7 @@
         # create share network
         created = self.shares_client.create_share_network(
             **data)['share_network']
-        self.assertDictContainsSubset(data, created)
+        self.assertLessEqual(data.items(), created.items())
 
         # Delete share_network
         self.shares_client.delete_share_network(created["id"])
@@ -237,7 +237,7 @@
         self.assertEqual('2002-02-02T00:00:00.000000', get['created_at'])
         data = self.data_sn_with_ldap_ss.copy()
         del data['created_at']
-        self.assertDictContainsSubset(data, get)
+        self.assertLessEqual(data.items(), get.items())
 
     @decorators.idempotent_id('1837fdd3-8068-4e88-bc50-9224498f84c0')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
@@ -246,7 +246,7 @@
         updated = self.shares_client.update_share_network(
             self.sn_with_ldap_ss["id"],
             **update_data)['share_network']
-        self.assertDictContainsSubset(update_data, updated)
+        self.assertLessEqual(update_data.items(), updated.items())
 
     @decorators.idempotent_id('198a5c08-3aaf-4623-9720-95d33ebe3376')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -262,7 +262,7 @@
         updated = self.shares_client.update_share_network(
             self.shares_client.share_network_id,
             **update_dict)['share_network']
-        self.assertDictContainsSubset(update_dict, updated)
+        self.assertLessEqual(update_dict.items(), updated.items())
 
     @decorators.idempotent_id('7595a844-a28e-476c-89f1-4d3193ce9d5b')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
@@ -272,14 +272,14 @@
 
         # create share network
         sn1 = self.shares_client.create_share_network(**data)['share_network']
-        self.assertDictContainsSubset(data, sn1)
+        self.assertLessEqual(data.items(), sn1.items())
 
         # Delete first share network
         self.shares_client.delete_share_network(sn1["id"])
 
         # create second share network with same data
         sn2 = self.shares_client.create_share_network(**data)['share_network']
-        self.assertDictContainsSubset(data, sn2)
+        self.assertLessEqual(data.items(), sn2.items())
 
         # Delete second share network
         self.shares_client.delete_share_network(sn2["id"])
@@ -292,11 +292,11 @@
 
         # create first share network
         sn1 = self.create_share_network(**data)
-        self.assertDictContainsSubset(data, sn1)
+        self.assertLessEqual(data.items(), sn1.items())
 
         # create second share network
         sn2 = self.create_share_network(**data)
-        self.assertDictContainsSubset(data, sn2)
+        self.assertLessEqual(data.items(), sn2.items())
 
     @decorators.idempotent_id('2dbf91da-04ae-4f9f-a7b9-0299c6b2e02c')
     @testtools.skipUnless(CONF.share.create_networks_when_multitenancy_enabled,
diff --git a/manila_tempest_tests/tests/api/test_share_networks_negative.py b/manila_tempest_tests/tests/api/test_share_networks_negative.py
index 94fa7b8..77866dd 100644
--- a/manila_tempest_tests/tests/api/test_share_networks_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_networks_negative.py
@@ -90,7 +90,7 @@
     def test_try_get_deleted_share_network(self):
         data = utils.generate_share_network_data()
         sn = self.create_share_network(**data)
-        self.assertDictContainsSubset(data, sn)
+        self.assertLessEqual(data.items(), sn.items())
 
         self.shares_client.delete_share_network(sn["id"])
 
diff --git a/manila_tempest_tests/tests/api/test_shares_actions.py b/manila_tempest_tests/tests/api/test_shares_actions.py
index 1b987ae..aa60d84 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions.py
@@ -310,8 +310,8 @@
         # verify response
         self.assertGreater(len(shares), 0)
         for share in shares:
-            self.assertDictContainsSubset(
-                filters['metadata'], share['metadata'])
+            self.assertLessEqual(filters['metadata'].items(),
+                                 share['metadata'].items())
         if CONF.share.capability_create_share_from_snapshot_support:
             self.assertFalse(self.shares[1]['id'] in [s['id'] for s in shares])
 
diff --git a/manila_tempest_tests/tests/rbac/test_rules.py b/manila_tempest_tests/tests/rbac/test_rules.py
index 8a6d46f..4c86787 100644
--- a/manila_tempest_tests/tests/rbac/test_rules.py
+++ b/manila_tempest_tests/tests/rbac/test_rules.py
@@ -58,10 +58,10 @@
         access['access_level'] = access_level
         return access
 
-    def allow_access(self, client, share_id, access_type, access_to,
-                     access_level='rw', metadata=None, status='active',
-                     cleanup=True):
-
+    def allow_access(self, client, share_id, access_level='rw', metadata=None,
+                     status='active', cleanup=True):
+        access_type, access_to = (
+            utils.get_access_rule_data_from_config(self.protocol))
         kwargs = {
             'access_type': access_type,
             'access_to': access_to,
@@ -93,6 +93,10 @@
         pass
 
     @abc.abstractmethod
+    def test_update_access(self):
+        pass
+
+    @abc.abstractmethod
     def test_delete_access(self):
         pass
 
@@ -127,35 +131,27 @@
     @decorators.idempotent_id('5b6897d1-4b2a-490c-990e-941ea4893f47')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_get_access(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type, access_to=access_to)
+            self.share_member_client, self.share['id'])
         self.do_request(
             'get_access_rule', expected_status=200, access_id=access['id'])
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         self.do_request(
             'get_access_rule', expected_status=200, access_id=alt_access['id'])
 
     @decorators.idempotent_id('f8e9a2bb-ccff-4fc5-8d61-2930f87406cd')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_list_access(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type, access_to=access_to)
+            self.share_member_client, self.share['id'])
         access_list = self.do_request(
             'list_access_rules', expected_status=200,
             share_id=self.share['id'])['access_list'][0]['id']
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         alt_access_list = self.do_request(
             'list_access_rules', expected_status=200,
             share_id=self.share['id'])['access_list'][0]['id']
@@ -163,6 +159,33 @@
         self.assertIn(access['id'], access_list)
         self.assertNotIn(alt_access['id'], alt_access_list)
 
+    @utils.skip_if_microversion_not_supported('2.88')
+    @decorators.idempotent_id('01939b69-ef9b-75cf-abf7-5171fec7c397')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_access(self):
+        access_type, access_to = (
+            utils.get_access_rule_data_from_config(self.protocol))
+        if access_type != 'ip':
+            msg = "Access rule updates supported only for 'ip' access."
+            raise self.skipException(msg)
+
+        access = self.allow_access(self.share_member_client, self.share['id'])
+        rule = self.do_request(
+            'update_access_rule', expected_status=200,
+            access_id=access['id'], access_level='ro')['access']
+        waiters.wait_for_resource_status(
+            self.share_member_client, self.share['id'], status='active',
+            resource_name='access_rule', rule_id=rule['id'])
+
+        alt_access = self.allow_access(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        rule = self.do_request(
+            'update_access_rule', expected_status=200,
+            access_id=alt_access['id'], access_level='ro')['access']
+        waiters.wait_for_resource_status(
+            self.alt_project_share_v2_client, self.alt_share['id'],
+            status='active', resource_name='access_rule', rule_id=rule['id'])
+
     @decorators.idempotent_id('b4d7a91c-a75e-4ad9-93cb-8e5234fea97a')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_grant_access_rule(self):
@@ -180,6 +203,8 @@
         self.addCleanup(
             self.client.delete_access_rule, self.share['id'], access['id'])
 
+        access_type, access_to = (
+            utils.get_access_rule_data_from_config(self.protocol))
         alt_access = self.do_request(
             'create_access_rule', expected_status=200,
             **self.access(
@@ -197,12 +222,8 @@
     @decorators.idempotent_id('e24d7018-cb49-4306-9947-716b4e4250c5')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_delete_access(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type,
-            access_to=access_to, cleanup=False)
+            self.share_member_client, self.share['id'], cleanup=False)
         self.do_request(
             'delete_access_rule', expected_status=202,
             share_id=self.share['id'], rule_id=access['id'])
@@ -211,7 +232,6 @@
 
         alt_access = self.allow_access(
             self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to,
             cleanup=False)
         self.do_request(
             'delete_access_rule', expected_status=202,
@@ -222,18 +242,14 @@
     @decorators.idempotent_id('ffc07445-d0d1-4bf9-9fbc-4f409d48bccd')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_update_access_rule_metadata(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type, access_to=access_to)
+            self.share_member_client, self.share['id'])
         self.do_request(
             'update_access_metadata', expected_status=200,
             access_id=access['id'], metadata=self.metadata)
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         self.do_request(
             'update_access_metadata', expected_status=200,
             access_id=alt_access['id'], metadata=self.metadata)
@@ -241,19 +257,14 @@
     @decorators.idempotent_id('fd580d91-1d8d-4dd0-8484-01c412ddb768')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_delete_access_rule_metadata(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type, access_to=access_to,
-            metadata=self.metadata)
+            self.share_member_client, self.share['id'], metadata=self.metadata)
         self.do_request(
             'delete_access_metadata', expected_status=200,
             access_id=access['id'], key='key')
 
         alt_access = self.allow_access(
             self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to,
             metadata=self.metadata)
         self.do_request(
             'delete_access_metadata', expected_status=200,
@@ -276,18 +287,13 @@
     @decorators.idempotent_id('de643909-88a2-470b-8a14-0417696ec451')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_get_access(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         share_client = getattr(self, 'share_member_client', self.client)
-        access = self.allow_access(
-            share_client, self.share['id'], access_type=access_type,
-            access_to=access_to)
+        access = self.allow_access(share_client, self.share['id'])
         self.do_request(
             'get_access_rule', expected_status=200, access_id=access['id'])
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         self.do_request(
             'get_access_rule', expected_status=lib_exc.NotFound,
             access_id=alt_access['id'])
@@ -295,15 +301,10 @@
     @decorators.idempotent_id('7c6c4262-5095-4cd7-9d9c-8064009a9055')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_list_access(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         share_client = getattr(self, 'share_member_client', self.client)
-        access = self.allow_access(
-            share_client, self.share['id'], access_type=access_type,
-            access_to=access_to)
+        access = self.allow_access(share_client, self.share['id'])
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
 
         access_list = self.do_request(
             'list_access_rules', expected_status=200,
@@ -315,6 +316,31 @@
         self.assertIn(access['id'], access_id_list)
         self.assertNotIn(alt_access['id'], access_id_list)
 
+    @utils.skip_if_microversion_not_supported('2.88')
+    @decorators.idempotent_id('02939b69-ef9b-75cf-abf7-5171fec7c397')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_access(self):
+        access_type, access_to = (
+            utils.get_access_rule_data_from_config(self.protocol))
+        if access_type != 'ip':
+            msg = "Access rule updates supported only for 'ip' access."
+            raise self.skipException(msg)
+
+        share_client = getattr(self, 'share_member_client', self.client)
+        access = self.allow_access(share_client, self.share['id'])
+        rule = self.do_request(
+            'update_access_rule', client=share_client, expected_status=200,
+            access_id=access['id'], access_level='ro')['access']
+        waiters.wait_for_resource_status(
+            share_client, self.share['id'], status='active',
+            resource_name='access_rule', rule_id=rule['id'])
+
+        alt_access = self.allow_access(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'update_access_rule', expected_status=lib_exc.NotFound,
+            access_id=alt_access['id'], access_level='ro')
+
     @decorators.idempotent_id('61cf6f6c-5d7c-48d7-9d5a-e6ea288afdbc')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_grant_access_rule(self):
@@ -333,6 +359,8 @@
         self.addCleanup(
             self.client.delete_access_rule, self.share['id'], access['id'])
 
+        access_type, access_to = (
+            utils.get_access_rule_data_from_config(self.protocol))
         self.do_request(
             'create_access_rule', client=share_client,
             expected_status=lib_exc.NotFound,
@@ -341,12 +369,9 @@
     @decorators.idempotent_id('8665d1b1-de4c-42d4-93ff-8dc6d2b73a2d')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_delete_access(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         share_client = getattr(self, 'share_member_client', self.client)
         access = self.allow_access(
-            share_client, self.share['id'], access_type=access_type,
-            access_to=access_to, cleanup=False)
+            share_client, self.share['id'], cleanup=False)
         self.do_request(
             'delete_access_rule', expected_status=202,
             share_id=self.share['id'], rule_id=access['id'])
@@ -354,8 +379,7 @@
             rule_id=access['id'], share_id=self.share['id'])
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         self.do_request(
             'delete_access_rule', expected_status=lib_exc.NotFound,
             share_id=self.alt_share['id'], rule_id=alt_access['id'])
@@ -363,19 +387,14 @@
     @decorators.idempotent_id('c5e84362-6075-425b-bfa3-898abfd9d5a0')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_update_access_rule_metadata(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         share_client = getattr(self, 'share_member_client', self.client)
-        access = self.allow_access(
-            share_client, self.share['id'], access_type=access_type,
-            access_to=access_to)
+        access = self.allow_access(share_client, self.share['id'])
         self.do_request(
             'update_access_metadata', expected_status=200,
             access_id=access['id'], metadata=self.metadata)
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         self.do_request(
             'update_access_metadata', expected_status=lib_exc.NotFound,
             access_id=alt_access['id'], metadata=self.metadata)
@@ -383,19 +402,15 @@
     @decorators.idempotent_id('abb17315-6510-4b6e-ae6c-dd99a6088954')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_delete_access_rule_metadata(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         share_client = getattr(self, 'share_member_client', self.client)
         access = self.allow_access(
-            share_client, self.share['id'], access_type=access_type,
-            access_to=access_to, metadata=self.metadata)
+            share_client, self.share['id'], metadata=self.metadata)
         self.do_request(
             'delete_access_metadata', expected_status=200,
             access_id=access['id'], key='key')
 
         alt_access = self.allow_access(
             self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to,
             metadata=self.metadata)
         self.do_request(
             'delete_access_metadata', expected_status=lib_exc.NotFound,
@@ -432,6 +447,20 @@
     def test_list_access(self):
         super(TestProjectReaderTestsNFS, self).test_list_access()
 
+    @decorators.idempotent_id('03939b69-ef9b-75cf-abf7-5171fec7c397')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_access(self):
+        access = self.allow_access(self.share_member_client, self.share['id'])
+        self.do_request(
+            'update_access_rule', expected_status=lib_exc.Forbidden,
+            access_id=access['id'], access_level='ro')
+
+        alt_access = self.allow_access(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'update_access_rule', expected_status=lib_exc.Forbidden,
+            access_id=alt_access['id'], access_level='ro')
+
     @decorators.idempotent_id('ace870f9-af91-4259-8760-dc7d7107b7ff')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_grant_access_rule(self):
@@ -441,6 +470,8 @@
             'create_access_rule', expected_status=lib_exc.Forbidden,
             **self.access(self.share['id'], access_type, access_to))
 
+        access_type, access_to = (
+            utils.get_access_rule_data_from_config(self.protocol))
         self.do_request(
             'create_access_rule', expected_status=lib_exc.Forbidden,
             **self.access(self.alt_share['id'], access_type, access_to))
@@ -448,18 +479,13 @@
     @decorators.idempotent_id('7a702c74-8d31-49e3-859a-cc8a78d7915e')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_delete_access(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
-        access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type, access_to=access_to)
+        access = self.allow_access(self.share_member_client, self.share['id'])
         self.do_request(
             'delete_access_rule', expected_status=lib_exc.Forbidden,
             share_id=self.share['id'], rule_id=access['id'])
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         self.do_request(
             'delete_access_rule', expected_status=lib_exc.Forbidden,
             share_id=self.alt_share['id'], rule_id=alt_access['id'])
@@ -467,18 +493,13 @@
     @decorators.idempotent_id('a61d7f06-6f0e-4da3-b11d-1c3a0b5bd416')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_update_access_rule_metadata(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
-        access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type, access_to=access_to)
+        access = self.allow_access(self.share_member_client, self.share['id'])
         self.do_request(
             'update_access_metadata', expected_status=lib_exc.Forbidden,
             access_id=access['id'], metadata=self.metadata)
 
         alt_access = self.allow_access(
-            self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to)
+            self.alt_project_share_v2_client, self.alt_share['id'])
         self.do_request(
             'update_access_metadata', expected_status=lib_exc.Forbidden,
             access_id=alt_access['id'], metadata=self.metadata)
@@ -486,19 +507,14 @@
     @decorators.idempotent_id('5faf0e0b-b246-4392-901d-9e7d628f0d6e')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_delete_access_rule_metadata(self):
-        access_type, access_to = (
-            utils.get_access_rule_data_from_config(self.protocol))
         access = self.allow_access(
-            self.share_member_client, self.share['id'],
-            access_type=access_type, access_to=access_to,
-            metadata=self.metadata)
+            self.share_member_client, self.share['id'], metadata=self.metadata)
         self.do_request(
             'delete_access_metadata', expected_status=lib_exc.Forbidden,
             access_id=access['id'], key='key')
 
         alt_access = self.allow_access(
             self.alt_project_share_v2_client, self.alt_share['id'],
-            access_type=access_type, access_to=access_to,
             metadata=self.metadata)
         self.do_request(
             'delete_access_metadata', expected_status=lib_exc.Forbidden,
diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py
index 3e06323..f9df340 100644
--- a/manila_tempest_tests/tests/scenario/manager_share.py
+++ b/manila_tempest_tests/tests/scenario/manager_share.py
@@ -186,7 +186,7 @@
                         storage_net_nic[0]['addr']
                     )
             # Attach a floating IP
-            self.associate_floating_ip(floating_ip, instance)
+            self.associate_floating_ip(floating_ip, instance, ip_addr=ip_addr)
 
         self.assertIsNotNone(server_ip)
         # Check ssh
@@ -752,8 +752,11 @@
         self.validate_ping_to_export_location(location, ssh_client)
 
         target_dir = target_dir or "/mnt"
+        nfs_version = getattr(self, 'nfs_version', None)
+        version_option = f"-o vers={nfs_version}" if nfs_version else ""
         ssh_client.exec_command(
-            "sudo mount -vt nfs \"%s\" %s" % (location, target_dir)
+            "sudo mount -vt nfs %s \"%s\" %s" % (
+                version_option, location, target_dir)
         )
 
 
diff --git a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
index d832974..e7402ef 100644
--- a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
+++ b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
@@ -417,32 +417,41 @@
             "sudo touch %s/file3" % snapshot_dir)
 
 
+@ddt.ddt
 class TestShareBasicOpsNFS(manager.BaseShareScenarioNFSTest,
                            ShareBasicOpsBase):
-    pass
+
+    @decorators.idempotent_id('4bad2073-a19b-4851-8cbe-75b20ade5cdb')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+    @ddt.data(*utils.deduplicate(CONF.share.nfs_versions))
+    def test_mount_share_one_vm(self, nfs_version):
+        self.nfs_version = nfs_version
+        super(TestShareBasicOpsNFS, self).test_mount_share_one_vm()
 
 
 class TestShareBasicOpsCIFS(manager.BaseShareScenarioCIFSTest,
                             ShareBasicOpsBase):
 
+    @testtools.skipIf(
+        "cifs" not in CONF.share.enable_ro_access_level_for_protocols,
+        "RO access rule tests are disabled for CIFS protocol.")
     @decorators.idempotent_id('4344a47a-d316-496b-97a4-12a59297950a')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
     def test_write_with_ro_access(self):
-        msg = ("Skipped for CIFS protocol because RO access is not "
-               "supported for shares by IP.")
-        raise self.skipException(msg)
+        super(TestShareBasicOpsCIFS, self).test_write_with_ro_access()
 
+    @decorators.skip_because(bug='1649573')
     @decorators.idempotent_id('a691332b-dd7a-4041-9bbd-3893e168aefa')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     def test_read_mountable_snapshot(self):
-        msg = "Skipped for CIFS protocol because of bug/1649573"
-        raise self.skipException(msg)
+        super(TestShareBasicOpsCIFS, self).test_read_mountable_snapshot()
 
+    @decorators.skip_because(bug='1649573')
     @decorators.idempotent_id('8c936c3e-4793-49d2-8409-4038f03e7012')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     def test_write_data_to_share_created_from_snapshot(self):
-        msg = "Skipped for CIFS protocol because of bug/1649573"
-        raise self.skipException(msg)
+        super(TestShareBasicOpsCIFS,
+              self).test_write_data_to_share_created_from_snapshot()
 
 
 class TestBaseShareBasicOpsScenarioCEPHFS(manager.BaseShareScenarioCEPHFSTest,
diff --git a/manila_tempest_tests/tests/scenario/test_share_extend.py b/manila_tempest_tests/tests/scenario/test_share_extend.py
index 450d2d4..39098dc 100644
--- a/manila_tempest_tests/tests/scenario/test_share_extend.py
+++ b/manila_tempest_tests/tests/scenario/test_share_extend.py
@@ -9,6 +9,7 @@
 #    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 time
 
 import ddt
 from oslo_log import log as logging
@@ -50,6 +51,8 @@
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     def test_create_extend_and_write(self):
         default_share_size = CONF.share.share_size
+        additional_overflow_blocks = CONF.share.additional_overflow_blocks
+        share_growth_size = CONF.share.share_growth_size
 
         LOG.debug('Step 1 - create instance')
         instance = self.boot_instance(wait_until="BUILD")
@@ -77,30 +80,36 @@
         self.write_data_to_mounted_share_using_dd(remote_client,
                                                   '/mnt/t1', '64M',
                                                   three_quarter_blocks)
+        time.sleep(CONF.share.share_resize_sync_delay)
         ls_result = remote_client.exec_command("sudo ls -lAh /mnt/")
         LOG.debug(ls_result)
 
-        over_one_quarter_blocks = total_blocks - three_quarter_blocks + 5
+        # Additional blocks that exceed the share capacity, defaulting to 5.
+        overflow_blocks = (
+            total_blocks - three_quarter_blocks +
+            additional_overflow_blocks or 5)
         LOG.debug('Step 6b - Write more data, should fail')
         self.assertRaises(
             exceptions.SSHExecCommandFailed,
             self.write_data_to_mounted_share_using_dd,
-            remote_client, '/mnt/t2', '64M', over_one_quarter_blocks)
+            remote_client, '/mnt/t2', '64M', overflow_blocks)
+        time.sleep(CONF.share.share_resize_sync_delay)
         ls_result = remote_client.exec_command("sudo ls -lAh /mnt/")
         LOG.debug(ls_result)
 
         LOG.debug('Step 7 - extend and wait')
-        extended_share_size = default_share_size + 1
+        extended_share_size = default_share_size + share_growth_size
         self.shares_v2_client.extend_share(share["id"],
                                            new_size=extended_share_size)
         waiters.wait_for_resource_status(
             self.shares_v2_client, share["id"], constants.STATUS_AVAILABLE)
         share = self.shares_v2_client.get_share(share["id"])['share']
         self.assertEqual(extended_share_size, int(share["size"]))
+        time.sleep(CONF.share.share_resize_sync_delay)
 
         LOG.debug('Step 8 - writing more data, should succeed')
         self.write_data_with_remount(location, remote_client, '/mnt/t3',
-                                     '64M', over_one_quarter_blocks)
+                                     '64M', overflow_blocks)
         ls_result = remote_client.exec_command("sudo ls -lAh /mnt/")
         LOG.debug(ls_result)
 
diff --git a/manila_tempest_tests/tests/scenario/test_share_shrink.py b/manila_tempest_tests/tests/scenario/test_share_shrink.py
index fab7e0a..431bfc2 100644
--- a/manila_tempest_tests/tests/scenario/test_share_shrink.py
+++ b/manila_tempest_tests/tests/scenario/test_share_shrink.py
@@ -80,6 +80,7 @@
         self.write_data_to_mounted_share_using_dd(remote_client,
                                                   '/mnt/t1', '64M',
                                                   blocks)
+        time.sleep(CONF.share.share_resize_sync_delay)
         ls_result = remote_client.exec_command("sudo ls -lAh /mnt/")
         LOG.debug(ls_result)
 
@@ -117,10 +118,11 @@
         self.assertEqual(default_share_size, int(share["size"]))
 
         LOG.debug('Step 11 - write more data than allocated, should fail')
+        overflow_blocks = blocks + CONF.share.additional_overflow_blocks
         self.assertRaises(
             exceptions.SSHExecCommandFailed,
             self.write_data_to_mounted_share_using_dd,
-            remote_client, '/mnt/t1', '64M', blocks)
+            remote_client, '/mnt/t1', '64M', overflow_blocks)
 
         LOG.debug('Step 12 - unmount')
         self.unmount_share(remote_client)
diff --git a/releasenotes/notes/add-update-access-rules-e43b4d0fbabdb596.yaml b/releasenotes/notes/add-update-access-rules-e43b4d0fbabdb596.yaml
new file mode 100644
index 0000000..29b2936
--- /dev/null
+++ b/releasenotes/notes/add-update-access-rules-e43b4d0fbabdb596.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Added tests to verify share access rule update operation. Update is
+    allowed only for admin and project member. Also supported microversion is
+    increased to 2.88.
diff --git a/releasenotes/notes/bug-2006792-fix-stop-cleanup-error-2a314862576f655b.yaml b/releasenotes/notes/bug-2006792-fix-stop-cleanup-error-2a314862576f655b.yaml
new file mode 100644
index 0000000..aaa3105
--- /dev/null
+++ b/releasenotes/notes/bug-2006792-fix-stop-cleanup-error-2a314862576f655b.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Fixed bug #2006792. Now the clear resources function has an error
+    treatment to avoid time out exceptions. Also fix the returned
+    object in the _is_resource_deleted function
diff --git a/releasenotes/notes/drop-python38-support-07c1fab194bad54a.yaml b/releasenotes/notes/drop-python38-support-07c1fab194bad54a.yaml
new file mode 100644
index 0000000..70f3814
--- /dev/null
+++ b/releasenotes/notes/drop-python38-support-07c1fab194bad54a.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - |
+    Python 3.8 support has been dropped. Last release of
+    manila-tempest-plugin to support python 3.8 is 2.5.0.
+    The minimum version of Python now supported is Python 3.9.
diff --git a/releasenotes/notes/nfs-versions-6886a2dd1bab094f.yaml b/releasenotes/notes/nfs-versions-6886a2dd1bab094f.yaml
new file mode 100644
index 0000000..b18d197
--- /dev/null
+++ b/releasenotes/notes/nfs-versions-6886a2dd1bab094f.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+  - |
+    A new configuration option, nfs_version, has been added to control
+    the NFS protocol version used for mounting NFS shares during testing.
+    This option allows users to specify which version of NFS should be used,
+    supporting environments where compatibility with specific versions is
+    required.
diff --git a/setup.cfg b/setup.cfg
index 457bfc2..f1c8312 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -6,6 +6,7 @@
 author = OpenStack
 author_email = openstack-discuss@lists.openstack.org
 home_page = https://docs.openstack.org/manila/latest/
+python_requires = >=3.9
 classifier =
     Environment :: OpenStack
     Intended Audience :: Information Technology
@@ -14,10 +15,10 @@
     Operating System :: POSIX :: Linux
     Programming Language :: Python
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.5
-    Programming Language :: Python :: 3.6
-    Programming Language :: Python :: 3.7
-    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
+    Programming Language :: Python :: 3.10
+    Programming Language :: Python :: 3.11
+    Programming Language :: Python :: 3.12
 
 [files]
 packages =
diff --git a/test-requirements.txt b/test-requirements.txt
index 761bf70..1a63b32 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,9 +1,8 @@
-hacking>=3.0.1,<3.1.0 # Apache-2.0
+hacking>=6.1.0,<6.2.0 # Apache-2.0
 
 coverage>=4.4.1 # Apache-2.0
 python-subunit>=1.0.0 # Apache-2.0/BSD
 oslotest>=3.2.0 # Apache-2.0
 stestr>=1.0.0 # Apache-2.0
 testtools>=2.2.0 # MIT
-# releasenotes
-flake8-import-order
+flake8-import-order>=0.18.0,<0.19.0 # LGPLv3
diff --git a/tox.ini b/tox.ini
index 907516f..1cf0c94 100644
--- a/tox.ini
+++ b/tox.ini
@@ -6,7 +6,6 @@
 basepython = python3
 usedevelop = True
 setenv =
-   VIRTUAL_ENV={envdir}
    PYTHONWARNINGS=default::DeprecationWarning
    OS_STDOUT_CAPTURE=1
    OS_STDERR_CAPTURE=1
diff --git a/zuul.d/manila-tempest-jobs.yaml b/zuul.d/manila-tempest-jobs.yaml
index 9a55fff..36a1faf 100644
--- a/zuul.d/manila-tempest-jobs.yaml
+++ b/zuul.d/manila-tempest-jobs.yaml
@@ -16,6 +16,7 @@
       - ^doc/.*$
       - ^manila/hacking/.*$
       - ^manila/tests/.*$
+      - ^\.pre-commit-config\.yaml$
       - ^releasenotes/.*$
       - ^setup.cfg$
       - ^tools/.*$
@@ -163,6 +164,8 @@
     name: manila-tempest-plugin-zfsonlinux
     description: Test ZFSOnLinux multibackend (DHSS=False) with postgresql db
     parent: manila-tempest-plugin-zfsonlinux-base
+    # https://bugs.launchpad.net/manila/+bug/2087192
+    nodeset: openstack-single-node-jammy
     branches: &ubuntu_jammy_test_image_branches
       regex: ^stable/(yoga|xena|wallaby|victoria|ussuri)$
       negate: true
@@ -174,8 +177,8 @@
       environment with IPv6 control plane endpoints.
     parent: manila-tempest-plugin-ipv6-base
     abstract: true
-    required-projects:
-      - openstack/neutron-dynamic-routing
+    # TODO(carloss): enable neutron-dynamic-routing setup when LP #1998489
+    # is fixed.
     vars:
       tempest_test_regex: '(^manila_tempest_tests.tests)(?=.*\[.*\bbackend\b.*\])'
       devstack_services: &devstack-with-ovs
@@ -214,8 +217,8 @@
         MANILA_SETUP_IPV6: true
         NEUTRON_CREATE_INITIAL_NETWORKS: false
         MANILA_RESTORE_IPV6_DEFAULT_ROUTE: false
-      devstack_plugins:
-        neutron-dynamic-routing: https://opendev.org/openstack/neutron-dynamic-routing
+      # TODO(carloss): enable neutron-dynamic-routing setup when LP #1998489
+      # is fixed.
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
@@ -249,6 +252,18 @@
         MANILA_SETUP_IPV6: false
         NEUTRON_CREATE_INITIAL_NETWORKS: true
 
+
+# TODO(gmann): As per the 2025.1 testing runtime, we need to run at least
+# one job on jammy. This job can be removed as per the future testing
+# runtime (whenever we start testing Ubuntu 26.04 as default version).
+- job:
+    name: manila-tempest-plugin-lvm-jammy
+    description: This is integrated job testing on Ubuntu jammy(22.04)
+    parent: manila-tempest-plugin-lvm
+    nodeset: openstack-single-node-jammy
+    branches:
+      - stable/2025.1
+
 - job:
     name: manila-tempest-plugin-container
     description: |
@@ -376,6 +391,10 @@
         devstack-plugin-ceph: https://opendev.org/openstack/devstack-plugin-ceph
       tempest_test_regex: manila_tempest_tests.tests
       devstack_localrc:
+        # TODO (gouthamr): update to squid after
+        # https://bugs.launchpad.net/manila/+bug/2105833
+        CEPH_RELEASE: 'reef'
+        CONTAINER_IMAGE: 'quay.io/ceph/ceph:v18.2'
         VOLUME_BACKING_FILE_SIZE: 60GB
         SHARE_DRIVER: manila.share.drivers.cephfs.driver.CephFSDriver
         MANILA_ENABLED_BACKENDS: cephfsnative
@@ -416,7 +435,12 @@
     vars:
       configure_swap_size: 8192
       tempest_test_regex: manila_tempest_tests.tests
-      tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*ceph_fuse.*)'
+      # NOTE(gouthamr): Avoiding ceph fuse tests to conserve resources;
+      # we're hoping we'd get sufficient coverage through kernel tests.
+      # test_extend_share: https://bugs.launchpad.net/manila/+bug/2075981
+      tempest_exclude_regex: "\
+        (^manila_tempest_tests.tests.scenario.*ceph_fuse.*)|\
+        (^manila_tempest_tests.tests.scenario.test_share_extend.*)"
       devstack_localrc:
         ENABLE_CEPH_NOVA: false
         CEPHADM_DEPLOY: true
@@ -434,7 +458,8 @@
     parent: manila-tempest-plugin-base
     required-projects:
       - openstack/devstack-plugin-ceph
-      - openstack/neutron-dynamic-routing
+      # TODO(carloss): enable neutron-dynamic-routing setup when LP #1998489
+      # is fixed.
     vars:
       tempest_concurrency: 2
       # turning off some tests due to exhaustion of disk space
@@ -445,7 +470,8 @@
       devstack_services: *devstack-with-ovs # LP 1940324
       devstack_plugins:
         devstack-plugin-ceph: https://opendev.org/openstack/devstack-plugin-ceph
-        neutron-dynamic-routing: https://opendev.org/openstack/neutron-dynamic-routing
+        # TODO(carloss): enable neutron-dynamic-routing setup when LP #1998489
+        # is fixed.
       devstack_localrc:
         # NOTE(gouthamr): LP#1940324 prevents bgp usage with OVN, use OVS
         Q_AGENT: openvswitch
@@ -488,9 +514,14 @@
     parent: manila-tempest-plugin-cephfs-nfs-base
     branches: *ubuntu_jammy_test_image_branches
     vars:
+      tempest_concurrency: 1
       # TODO(gouthamr): some tests are disabled due to bugs
       # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
-      tempest_exclude_regex: "(^manila_tempest_tests.tests.scenario.*IPv6.*)"
+      # test_share_extend: https://bugs.launchpad.net/manila/+bug/2075981
+      tempest_exclude_regex: "\
+        (^manila_tempest_tests.tests.scenario.*IPv6.*)|\
+        (^manila_tempest_tests.tests.scenario.test_share_extend.*)"
+      tempest_test_regex: '(^manila_tempest_tests.tests)(?=.*\[.*\bbackend\b.*\])'
       devstack_localrc:
         CEPHADM_DEPLOY: True
         CEPHADM_DEV_OSD: True
@@ -556,10 +587,14 @@
       tempest_concurrency: 2
         # TODO(gouthamr): some tests are disabled due to bugs
         # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
-      tempest_exclude_regex: "(^manila_tempest_tests.tests.scenario.*IPv6.*)"
+        # test_share_extend: https://bugs.launchpad.net/manila/+bug/2075981
+      tempest_exclude_regex: "\
+        (^manila_tempest_tests.tests.scenario.*IPv6.*)|\
+        (^manila_tempest_tests.tests.scenario.test_share_extend.*)"
       devstack_localrc:
         MYSQL_REDUCE_MEMORY: True
         CEPHADM_DEPLOY: True
+        ENABLE_INGRESS: False
         CEPHADM_DEV_OSD: true
         CEPH_LOOPBACK_DISK_SIZE: 40GB
         ENABLED_SHARE_PROTOCOLS: NFS
@@ -596,6 +631,7 @@
           devstack-plugin-ceph: https://opendev.org/openstack/devstack-plugin-ceph
         devstack_localrc:
           REMOTE_CEPH: True
+          ENABLE_CEPH_NOVA: False
       tempest:
         devstack_plugins:
           devstack-plugin-ceph: https://opendev.org/openstack/devstack-plugin-ceph
@@ -607,9 +643,15 @@
     vars:
       devstack_localrc:
         SHARE_DRIVER: manila.tests.share.drivers.dummy.DummyDriver
-        MANILA_CONFIGURE_GROUPS: alpha,beta,gamma,membernet
+        MANILA_CONFIGURE_GROUPS: alpha,beta,gamma,membernet,netapp_active_iq
         MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True revert_to_snapshot_support=True mount_snapshot_support=True'
         MANILA_ENABLED_BACKENDS: alpha,beta,gamma
+        MANILA_OPTGROUP_DEFAULT_scheduler_default_weighers: NetAppAIQWeigher,CapacityWeigher,GoodnessWeigher,HostAffinityWeigher,PoolWeigher
+        MANILA_OPTGROUP_netapp_active_iq_aiq_transport_type: https
+        MANILA_OPTGROUP_netapp_active_iq_aiq_ssl_verify: False
+        MANILA_OPTGROUP_netapp_active_iq_aiq_username: admin
+        MANILA_OPTGROUP_netapp_active_iq_aiq_password: 123
+        MANILA_OPTGROUP_netapp_active_iq_aiq_hostname: localhost
         MANILA_OPTGROUP_alpha_driver_handles_share_servers: false
         MANILA_OPTGROUP_alpha_replication_domain: DUMMY_DOMAIN
         MANILA_OPTGROUP_alpha_share_backend_name: ALPHA
@@ -665,10 +707,16 @@
     vars:
       devstack_localrc:
         SHARE_DRIVER: manila.tests.share.drivers.dummy.DummyDriver
-        MANILA_CONFIGURE_GROUPS: alpha,beta,gamma,membernet,adminnet
+        MANILA_CONFIGURE_GROUPS: alpha,beta,gamma,membernet,adminnet,netapp_active_iq
         MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True revert_to_snapshot_support=True mount_snapshot_support=True'
         MANILA_ENABLED_BACKENDS: alpha,beta
         MANILA_OPTGROUP_DEFAULT_quota_share_networks: 50
+        MANILA_OPTGROUP_DEFAULT_scheduler_default_weighers: NetAppAIQWeigher,CapacityWeigher,GoodnessWeigher,HostAffinityWeigher,PoolWeigher
+        MANILA_OPTGROUP_netapp_active_iq_aiq_transport_type: https
+        MANILA_OPTGROUP_netapp_active_iq_aiq_ssl_verify: False
+        MANILA_OPTGROUP_netapp_active_iq_aiq_username: admin
+        MANILA_OPTGROUP_netapp_active_iq_aiq_password: 123
+        MANILA_OPTGROUP_netapp_active_iq_aiq_hostname: localhost
         MANILA_OPTGROUP_adminnet_network_api_class: manila.network.standalone_network_plugin.StandaloneNetworkPlugin
         MANILA_OPTGROUP_adminnet_network_plugin_ipv4_enabled: true
         MANILA_OPTGROUP_adminnet_standalone_network_plugin_allowed_ip_ranges: 11.0.0.10-11.0.0.19,11.0.0.30-11.0.0.39,11.0.0.50-11.0.0.199
@@ -844,6 +892,7 @@
     check:
       jobs:
         - manila-tempest-plugin-lvm
+        - manila-tempest-plugin-lvm-jammy
         - manila-tempest-plugin-generic-scenario:
             voting: false
         - manila-tempest-plugin-generic:
@@ -857,3 +906,4 @@
     gate:
       jobs:
         - manila-tempest-plugin-lvm
+        - manila-tempest-plugin-lvm-jammy
diff --git a/zuul.d/manila-tempest-stable-jobs.yaml b/zuul.d/manila-tempest-stable-jobs.yaml
index 8a4495e..07f013a 100644
--- a/zuul.d/manila-tempest-stable-jobs.yaml
+++ b/zuul.d/manila-tempest-stable-jobs.yaml
@@ -69,7 +69,33 @@
     vars: *manila_tempest_image_pinned_vars
 
 - job:
-    name: manila-tempest-plugin-lvm-caracal
+    name: manila-tempest-plugin-lvm-2025.1
+    parent: manila-tempest-plugin-lvm-base
+    override-checkout: stable/2025.1
+    vars:
+      # TODO(gouthamr): some tests are disabled due to bugs
+      # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
+      # drop these overrides once we address that bug.
+      tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*IPv6.*)'
+      devstack_localrc:
+        MANILA_SETUP_IPV6: false
+        NEUTRON_CREATE_INITIAL_NETWORKS: true
+
+- job:
+    name: manila-tempest-plugin-lvm-2024.2
+    parent: manila-tempest-plugin-lvm-base
+    override-checkout: stable/2024.2
+    vars:
+      # TODO(gouthamr): some tests are disabled due to bugs
+      # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
+      # drop these overrides once we address that bug.
+      tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*IPv6.*)'
+      devstack_localrc:
+        MANILA_SETUP_IPV6: false
+        NEUTRON_CREATE_INITIAL_NETWORKS: true
+
+- job:
+    name: manila-tempest-plugin-lvm-2024.1
     parent: manila-tempest-plugin-lvm-base
     override-checkout: stable/2024.1
     vars:
@@ -81,37 +107,6 @@
         MANILA_SETUP_IPV6: false
         NEUTRON_CREATE_INITIAL_NETWORKS: true
 
-- job:
-    name: manila-tempest-plugin-lvm-bobcat
-    parent: manila-tempest-plugin-lvm-base
-    override-checkout: stable/2023.2
-    vars:
-      # TODO(gouthamr): some tests are disabled due to bugs
-      # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
-      # drop these overrides once we address that bug.
-      tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*IPv6.*)'
-      devstack_localrc:
-        MANILA_SETUP_IPV6: false
-        NEUTRON_CREATE_INITIAL_NETWORKS: true
-
-- job:
-    name: manila-tempest-plugin-lvm-antelope
-    parent: manila-tempest-plugin-lvm-base
-    override-checkout: stable/2023.1
-    vars:
-      # TODO(gouthamr): some tests are disabled due to bugs
-      # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
-      # drop these overrides once we address that bug.
-      tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*IPv6.*)'
-      devstack_localrc:
-        MANILA_SETUP_IPV6: false
-        NEUTRON_CREATE_INITIAL_NETWORKS: true
-        # NOTE(carloss): Pinning manila service image to a Focal version,
-        # since on Zed we moved to Ubuntu Jammy (22), and it requires more
-        # VM resources.
-        MANILA_SERVICE_IMAGE_URL: https://tarballs.opendev.org/openstack/manila-image-elements/images/manila-service-image-1.3.0-76-ga216835.qcow2
-        MANILA_SERVICE_IMAGE_NAME: manila-service-image-1.3.0-76-ga216835
-
 - project-template:
     name: manila-tempest-plugin-jobs-using-service-image-stable
     description: |
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index a6b15af..3ca5092 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -8,19 +8,13 @@
       jobs:
         - manila-tempest-plugin-dummy-no-dhss
         - manila-tempest-plugin-dummy-dhss
-        - manila-tempest-plugin-lvm-caracal
-        - manila-tempest-plugin-lvm-bobcat
-        - manila-tempest-plugin-lvm-antelope
+        - manila-tempest-plugin-lvm-2025.1
+        - manila-tempest-plugin-lvm-2024.2
+        - manila-tempest-plugin-lvm-2024.1
         - manila-tempest-plugin-dummy-no-dhss-rbac
         - manila-tempest-plugin-container:
             voting: false
-        - manila-tempest-plugin-glusterfs-nfs:
-            voting: false
     gate:
       jobs:
         - manila-tempest-plugin-dummy-no-dhss
         - manila-tempest-plugin-dummy-dhss
-    experimental:
-      jobs:
-        - manila-tempest-plugin-glusterfs-native:
-            voting: false