From 643083eefa3a08668928aa44ee1510a768f94b6a Mon Sep 17 00:00:00 2001
From: Ratnakaram Rajesh <rajesh.r@zadara.com>
Date: Mon, 15 Mar 2021 06:53:12 +0200
Subject: [PATCH] Support host assisted share migration for Zadara manila
 driver

Closes-Bug: #1917980

Change-Id: I66371e6a8a1650ffebe5ffe482cde52660ccc000
---
 manila/exception.py                           |  4 ++
 manila/share/drivers/zadara/zadara.py         | 63 +++++++++++++++----
 ...e-assisted-migration-2d8f8fdb51718faa.yaml |  6 ++
 3 files changed, 61 insertions(+), 12 deletions(-)
 create mode 100644 releasenotes/notes/bug-1917980-zadara-share-assisted-migration-2d8f8fdb51718faa.yaml

diff --git a/manila/exception.py b/manila/exception.py
index eec125d74d..0b3f327e6e 100644
--- a/manila/exception.py
+++ b/manila/exception.py
@@ -1096,3 +1096,7 @@ class ZadaraVPSASnapshotCreateFailed(ShareBackendException):
 class ZadaraVPSASnapshotManageFailed(ShareBackendException):
     message = _("Failed to manage VPSA share snapshot with id %(snap_id)s. "
                 "Error: %(error)s")
+
+
+class ZadaraServerNotFound(NotFound):
+    message = _("Unable to find server object for initiator %(name)s")
diff --git a/manila/share/drivers/zadara/zadara.py b/manila/share/drivers/zadara/zadara.py
index 2ccf8b1319..7e9d5b3f2a 100644
--- a/manila/share/drivers/zadara/zadara.py
+++ b/manila/share/drivers/zadara/zadara.py
@@ -66,9 +66,10 @@ class ZadaraVPSAShareDriver(driver.ShareDriver):
         20.12-22 - Addressing review comments from the manila community.
         20.12-23 - Addressing review comments from the manila community.
         20.12-24 - Addressing review comments from the manila community.
+        20.12-25 - Support host assisted share migration
     """
 
-    VERSION = '20.12-24'
+    VERSION = '20.12-25'
 
     # ThirdPartySystems wiki page
     CI_WIKI_NAME = "ZadaraStorage_VPSA_CI"
@@ -347,8 +348,13 @@ class ZadaraVPSAShareDriver(driver.ShareDriver):
     def _deny_access(self, context, share, access, share_server=None):
         """Deny access to the share from the host.
 
-        Auto detach from all servers.
         """
+        access_type = access['access_type']
+        if access_type != 'ip':
+            LOG.warning('Only ip access type is allowed for zadara vpsa.')
+            return
+        access_ip = access['access_to']
+
         # First: Check Active controller: if not valid, raise exception
         ctrl = self.vpsa._get_active_controller_details()
         if not ctrl:
@@ -358,18 +364,35 @@ class ZadaraVPSAShareDriver(driver.ShareDriver):
         share_name = self._get_zadara_share_template_name(share['id'])
         volume = self.vpsa._get_vpsa_volume(share_name)
         if not volume:
-            LOG.error('Volume %s could not be found.'
-                      'It might be already deleted', share['id'])
+            LOG.warning('Volume %s could not be found. '
+                        'It might be already deleted', share['id'])
             return
 
-        self.vpsa._detach_vpsa_volume(vpsa_vol=volume)
+        vpsa_srv = self.vpsa._get_server_name(access_ip, True)
+        if not vpsa_srv:
+            LOG.warning('VPSA server %s could not be found.', access_ip)
+            return
+
+        servers_list = self.vpsa._get_servers_attached_to_volume(volume)
+        if vpsa_srv not in servers_list:
+            LOG.warning('VPSA server %(access_ip)s not attached '
+                        'to volume %(volume)s.',
+                        {'access_ip': access_ip, 'volume': share['id']})
+            return
+
+        self.vpsa._detach_vpsa_volume(vpsa_vol=volume,
+                                      vpsa_srv=vpsa_srv)
 
     def update_access(self, context, share, access_rules, add_rules,
                       delete_rules, share_server=None):
         access_updates = {}
-        if add_rules:
-            # Add rules for accessing share
-            for access_rule in add_rules:
+        if not (add_rules or delete_rules):
+            # add_rules and delete_rules can be empty lists, in cases
+            # like share migration for zadara driver, when the access
+            # level is to be changed for all existing rules. For zadara
+            # backend, we delete and re-add all the existing rules.
+            for access_rule in access_rules:
+                self._deny_access(context, share, access_rule)
                 try:
                     self._allow_access(context, share, access_rule)
                 except manila_exception.ZadaraInvalidShareAccessType:
@@ -382,10 +405,26 @@ class ZadaraVPSAShareDriver(driver.ShareDriver):
                                'id': access_rule['access_id']})
                     access_updates.update(
                         {access_rule['access_id']: {'state': 'error'}})
-        if delete_rules:
-            # Delete access rules for provided share
-            for access_rule in delete_rules:
-                self._deny_access(context, share, access_rule)
+        else:
+            if add_rules:
+                # Add rules for accessing share
+                for access_rule in add_rules:
+                    try:
+                        self._allow_access(context, share, access_rule)
+                    except manila_exception.ZadaraInvalidShareAccessType:
+                        LOG.error("Only ip access type allowed for Zadara "
+                                  "share. Failed to allow %(access_level)s "
+                                  "access to %(access_to)s for rule %(id)s. "
+                                  "Setting rule to 'error' state.",
+                                  {'access_level': access_rule['access_level'],
+                                   'access_to': access_rule['access_to'],
+                                   'id': access_rule['access_id']})
+                        access_updates.update(
+                            {access_rule['access_id']: {'state': 'error'}})
+            if delete_rules:
+                # Delete access rules for provided share
+                for access_rule in delete_rules:
+                    self._deny_access(context, share, access_rule)
         return access_updates
 
     def extend_share(self, share, new_size, share_server=None):
diff --git a/releasenotes/notes/bug-1917980-zadara-share-assisted-migration-2d8f8fdb51718faa.yaml b/releasenotes/notes/bug-1917980-zadara-share-assisted-migration-2d8f8fdb51718faa.yaml
new file mode 100644
index 0000000000..0d0425d829
--- /dev/null
+++ b/releasenotes/notes/bug-1917980-zadara-share-assisted-migration-2d8f8fdb51718faa.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Fixed an issue in Zadara driver to support host assisted migration.
+    The existing access rules required to be updated with share migration
+    are deleted and re-added.