From fb4b0b86e98ff480eafd09ed33f7b7f6494b07d4 Mon Sep 17 00:00:00 2001
From: digvijay2016 <digvijay.ukirde@in.ibm.com>
Date: Thu, 22 Sep 2016 16:36:02 +0530
Subject: [PATCH] Add support for manage/unmanage in GPFS driver

Added support for manage/unmanage in GPFS NFS driver.
This patch added functions that allow share on Spectrum Scale
node to be managed by OpenStack if existing fileset is an
independent fileset and doesn't have any NFS export
over the fileset path. Also, share can be unmanaged from
OpenStack but still left in Spectrum Scale cluster.

Implements: blueprint gpfs-manage-support

Change-Id: I9134408b59c30ac4bc593f287294741f6e996136
---
 ...hare_back_ends_feature_support_mapping.rst |   2 +-
 etc/manila/rootwrap.d/share.filters           |   6 +
 manila/share/drivers/ibm/gpfs.py              | 205 +++++++++-
 manila/tests/share/drivers/ibm/test_gpfs.py   | 360 +++++++++++++++++-
 ...-gpfs-manage-support-c110120c350728e3.yaml |   8 +
 5 files changed, 564 insertions(+), 17 deletions(-)
 create mode 100644 releasenotes/notes/ibm-gpfs-manage-support-c110120c350728e3.yaml

diff --git a/doc/source/devref/share_back_ends_feature_support_mapping.rst b/doc/source/devref/share_back_ends_feature_support_mapping.rst
index 3ab154b144..cddec61975 100644
--- a/doc/source/devref/share_back_ends_feature_support_mapping.rst
+++ b/doc/source/devref/share_back_ends_feature_support_mapping.rst
@@ -61,7 +61,7 @@ Mapping of share drivers and share features support
 +----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
 |                 Huawei                 |           K           |           L           |       L      |       L      |            K           |              M             |            \-            |
 +----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
-|                IBM GPFS                |           K           |          \-           |       L      |      \-      |            K           |              K             |            \-            |
+|                IBM GPFS                |           K           |           O           |       L      |      \-      |            K           |              K             |            \-            |
 +----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
 |                  LVM                   |           M           |          \-           |       M      |      \-      |            M           |              M             |            \-            |
 +----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
diff --git a/etc/manila/rootwrap.d/share.filters b/etc/manila/rootwrap.d/share.filters
index 0941275749..6c5229a6fe 100644
--- a/etc/manila/rootwrap.d/share.filters
+++ b/etc/manila/rootwrap.d/share.filters
@@ -119,6 +119,12 @@ df: CommandFilter, df, root
 chmod: CommandFilter, chmod, root
 # manila/share/drivers/ibm/gpfs.py: 'mmnfs', 'export', '%s', '%s'
 mmnfs: CommandFilter, mmnfs, root
+# manila/share/drivers/ibm/gpfs.py: 'mmlsfileset', '%s', '-J', '%s', '-L'
+mmlsfileset: CommandFilter, mmlsfileset, root
+# manila/share/drivers/ibm/gpfs.py: 'mmchfileset', '%s', '-J', '%s', '-j', '%s'
+mmchfileset: CommandFilter, mmchfileset, root
+# manila/share/drivers/ibm/gpfs.py: 'mmlsquota', '-j', '-J', '%s', '%s'
+mmlsquota: CommandFilter, mmlsquota, root
 
 # manila/share/drivers/ganesha/manager.py: 'mv', '%s', '%s'
 mv: CommandFilter, mv, root
diff --git a/manila/share/drivers/ibm/gpfs.py b/manila/share/drivers/ibm/gpfs.py
index 621e767c09..13a48ffb5a 100644
--- a/manila/share/drivers/ibm/gpfs.py
+++ b/manila/share/drivers/ibm/gpfs.py
@@ -44,7 +44,7 @@ import six
 
 from manila.common import constants
 from manila import exception
-from manila.i18n import _
+from manila.i18n import _, _LI
 from manila.share import driver
 from manila.share.drivers.helpers import NFSHelper
 from manila.share import share_types
@@ -564,6 +564,178 @@ class GPFSShareDriver(driver.ExecuteMixin, driver.GaneshaMixin,
             LOG.error(msg)
             raise exception.InvalidParameterValue(err=msg)
 
+    def _is_share_valid(self, fsdev, location):
+        try:
+            out, __ = self._gpfs_execute('mmlsfileset', fsdev, '-J',
+                                         location, '-L', '-Y')
+        except exception.ProcessExecutionError:
+            msg = (_('Given share path %(share_path)s does not exist at '
+                     'mount point %(mount_point)s.')
+                   % {'share_path': location, 'mount_point': fsdev})
+            LOG.exception(msg)
+            raise exception.ManageInvalidShare(reason=msg)
+
+        lines = out.splitlines()
+        try:
+            validation_token = lines[0].split(':').index('allocInodes')
+            alloc_inodes = lines[1].split(':')[validation_token]
+        except (IndexError, ValueError):
+            msg = (_('Failed to check share at %s.') % location)
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+
+        return alloc_inodes != '0'
+
+    def _get_share_name(self, fsdev, location):
+        try:
+            out, __ = self._gpfs_execute('mmlsfileset', fsdev, '-J',
+                                         location, '-L', '-Y')
+        except exception.ProcessExecutionError:
+            msg = (_('Given share path %(share_path)s does not exist at '
+                     'mount point %(mount_point)s.')
+                   % {'share_path': location, 'mount_point': fsdev})
+            LOG.exception(msg)
+            raise exception.ManageInvalidShare(reason=msg)
+
+        lines = out.splitlines()
+        try:
+            validation_token = lines[0].split(':').index('filesetName')
+            share_name = lines[1].split(':')[validation_token]
+        except (IndexError, ValueError):
+            msg = (_('Failed to check share at %s.') % location)
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+
+        return share_name
+
+    def _manage_existing(self, fsdev, share, old_share_name):
+        new_share_name = share['name']
+        new_export_location = self._local_path(new_share_name)
+        try:
+            self._gpfs_execute('mmunlinkfileset', fsdev, old_share_name, '-f')
+        except exception.ProcessExecutionError:
+            msg = _('Failed to unlink fileset for share %s.') % new_share_name
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+        LOG.debug('Unlinked the fileset of share %s.', old_share_name)
+
+        try:
+            self._gpfs_execute('mmchfileset', fsdev, old_share_name,
+                               '-j', new_share_name)
+        except exception.ProcessExecutionError:
+            msg = _('Failed to rename fileset for share %s.') % new_share_name
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+        LOG.debug('Renamed the fileset from %(old_share)s to %(new_share)s.',
+                  {'old_share': old_share_name, 'new_share': new_share_name})
+
+        try:
+            self._gpfs_execute('mmlinkfileset', fsdev, new_share_name, '-J',
+                               new_export_location)
+        except exception.ProcessExecutionError:
+            msg = _('Failed to link fileset for the share %s.'
+                    ) % new_share_name
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+        LOG.debug('Linked the fileset of share %(share_name)s at location '
+                  '%(export_location)s.',
+                  {'share_name': new_share_name,
+                   'export_location': new_export_location})
+
+        try:
+            self._gpfs_execute('chmod', '777', new_export_location)
+        except exception.ProcessExecutionError:
+            msg = _('Failed to set permissions for share %s.') % new_share_name
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+        LOG.debug('Changed the permission of share %s.', new_share_name)
+
+        try:
+            out, __ = self._gpfs_execute('mmlsquota', '-j', new_share_name,
+                                         '-Y', fsdev)
+        except exception.ProcessExecutionError:
+            msg = _('Failed to check size for share %s.') % new_share_name
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+
+        lines = out.splitlines()
+        try:
+            quota_limit = lines[0].split(':').index('blockLimit')
+            quota_status = lines[1].split(':')[quota_limit]
+        except (IndexError, ValueError):
+            msg = _('Failed to check quota for share %s.') % new_share_name
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+
+        share_size = int(quota_status)
+        # Note: since share_size returns integer value in KB,
+        # we are checking whether share is less than 1GiB.
+        # (units.Mi * KB = 1GB)
+        if share_size < units.Mi:
+            try:
+                self._gpfs_execute('mmsetquota', fsdev + ':' + new_share_name,
+                                   '--block', '0:1G')
+            except exception.ProcessExecutionError:
+                msg = _('Failed to set quota for share %s.') % new_share_name
+                LOG.exception(msg)
+                raise exception.GPFSException(msg)
+            LOG.info(_LI('Existing share %(shr)s has size %(size)s KB '
+                         'which is below 1GiB, so extended it to 1GiB.') %
+                     {'shr': new_share_name, 'size': share_size})
+            share_size = 1
+        else:
+            orig_share_size = share_size
+            share_size = int(math.ceil(float(share_size) / units.Mi))
+            if orig_share_size != share_size * units.Mi:
+                try:
+                    self._gpfs_execute('mmsetquota', fsdev + ':' +
+                                       new_share_name, '--block', '0:' +
+                                       str(share_size) + 'G')
+                except exception.ProcessExecutionError:
+                    msg = _('Failed to set quota for share %s.'
+                            ) % new_share_name
+                    LOG.exception(msg)
+                    raise exception.GPFSException(msg)
+
+        new_export_location = self._get_helper(share).create_export(
+            new_export_location)
+        return share_size, new_export_location
+
+    def manage_existing(self, share, driver_options):
+
+        old_export = share['export_location'].split(':')
+        try:
+            ces_ip = old_export[0]
+            old_export_location = old_export[1]
+        except IndexError:
+            msg = _('Incorrect export path. Expected format: '
+                    'IP:/gpfs_mount_point_base/share_id.')
+            LOG.exception(msg)
+            raise exception.ShareBackendException(msg=msg)
+
+        if ces_ip not in self.configuration.gpfs_nfs_server_list:
+            msg = _('The CES IP %s is not present in the '
+                    'configuration option "gpfs_nfs_server_list".') % ces_ip
+            raise exception.ShareBackendException(msg=msg)
+
+        fsdev = self._get_gpfs_device()
+        if not self._is_share_valid(fsdev, old_export_location):
+            err_msg = _('Given share path %s does not have a valid '
+                        'share.') % old_export_location
+            raise exception.ManageInvalidShare(reason=err_msg)
+
+        share_name = self._get_share_name(fsdev, old_export_location)
+
+        out = self._get_helper(share)._has_client_access(old_export_location)
+        if out:
+            err_msg = _('Clients have access to %s share currently. Evict any '
+                        'clients before trying again.') % share_name
+            raise exception.ManageInvalidShare(reason=err_msg)
+
+        share_size, new_export_location = self._manage_existing(
+            fsdev, share, share_name)
+        return {"size": share_size, "export_locations": new_export_location}
+
     def _update_share_stats(self):
         """Retrieve stats info from share volume group."""
 
@@ -679,6 +851,23 @@ class KNFSHelper(NASHelperBase):
             LOG.error(msg)
             raise exception.GPFSException(msg)
 
+    def _has_client_access(self, local_path, access_to=None):
+        try:
+            out, __ = self._execute('exportfs', run_as_root=True)
+        except exception.ProcessExecutionError:
+            msg = _('Failed to check exports on the systems.')
+            LOG.exception(msg)
+            raise exception.GPFSException(msg)
+
+        if access_to:
+            if (re.search(re.escape(local_path) + '[\s\n]*'
+                          + re.escape(access_to), out)):
+                return True
+        else:
+            if re.findall(local_path + '\\b', ''.join(out)):
+                return True
+        return False
+
     def _publish_access(self, *cmd, **kwargs):
         check_exit_code = kwargs.get('check_exit_code', True)
 
@@ -739,19 +928,9 @@ class KNFSHelper(NASHelperBase):
             raise exception.InvalidShareAccess(reason='Only ip access type '
                                                       'supported.')
 
-        # check if present in export
-        try:
-            out, __ = self._execute('exportfs', run_as_root=True)
-        except exception.ProcessExecutionError as e:
-            msg = (_('Failed to check exports on the systems. '
-                     ' Error: %s.') % e)
-            LOG.error(msg)
-            raise exception.GPFSException(msg)
+        out = self._has_client_access(local_path, access['access_to'])
 
-        out = re.search(re.escape(local_path) + '[\s\n]*'
-                        + re.escape(access['access_to']), out)
-
-        if out is not None:
+        if out:
             access_type = access['access_type']
             access_to = access['access_to']
             raise exception.ShareAccessExists(access_type=access_type,
diff --git a/manila/tests/share/drivers/ibm/test_gpfs.py b/manila/tests/share/drivers/ibm/test_gpfs.py
index 0c4b1f429c..728a1d3155 100644
--- a/manila/tests/share/drivers/ibm/test_gpfs.py
+++ b/manila/tests/share/drivers/ibm/test_gpfs.py
@@ -45,6 +45,7 @@ class GPFSShareDriverTestCase(test.TestCase):
 
         self._helper_fake = mock.Mock()
         CONF.set_default('driver_handles_share_servers', False)
+        CONF.set_default('share_backend_name', 'GPFS')
         self.fake_conf = config.Configuration(None)
         self._driver = gpfs.GPFSShareDriver(execute=self._gpfs_execute,
                                             configuration=self.fake_conf)
@@ -55,6 +56,7 @@ class GPFSShareDriverTestCase(test.TestCase):
         self.fakedev = "/dev/gpfs0"
         self.fakefspath = "/gpfs0"
         self.fakesharepath = "/gpfs0/share-fakeid"
+        self.fakeexistingshare = "existingshare"
         self.fakesnapshotpath = "/gpfs0/.snapshots/snapshot-fakesnapshotid"
 
         self.fake_ces_exports = """
@@ -74,7 +76,8 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
         self._driver._helpers = {
             'KNFS': self._helper_fake
         }
-        self.share = fake_share.fake_share(share_proto='NFS')
+        self.share = fake_share.fake_share(share_proto='NFS',
+                                           host='fakehost@fakehost#GPFS')
         self.server = {
             'backend_details': {
                 'ip': '1.2.3.4',
@@ -86,7 +89,8 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
         self.local_ip = "192.11.22.1"
         self.remote_ip = "192.11.22.2"
         self.remote_ip2 = "2.2.2.2"
-        gpfs_nfs_server_list = [self.remote_ip, self.local_ip, self.remote_ip2]
+        gpfs_nfs_server_list = [self.remote_ip, self.local_ip, self.remote_ip2,
+                                "fake_location"]
         self._knfs_helper.configuration.gpfs_nfs_server_list = \
             gpfs_nfs_server_list
         self._ces_helper.configuration.gpfs_nfs_server_list = \
@@ -671,6 +675,333 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
             'rsync', '-rp', self.fakesnapshotpath + '/', self.fakesharepath
         )
 
+    @ddt.data("mmlsfileset::allocInodes:\nmmlsfileset::100096:",
+              "mmlsfileset::allocInodes:\nmmlsfileset::0:")
+    def test__is_share_valid_with_quota(self, fakeout):
+        self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
+
+        result = self._driver._is_share_valid(self.fakedev, self.fakesharepath)
+
+        self._driver._gpfs_execute.assert_called_once_with(
+            'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
+        if fakeout == "mmlsfileset::allocInodes:\nmmlsfileset::100096:":
+            self.assertTrue(result)
+        else:
+            self.assertFalse(result)
+
+    def test__is_share_valid_exception(self):
+        self._driver._gpfs_execute = mock.Mock(
+            side_effect=exception.ProcessExecutionError)
+
+        self.assertRaises(exception.ManageInvalidShare,
+                          self._driver._is_share_valid, self.fakedev,
+                          self.fakesharepath)
+
+        self._driver._gpfs_execute.assert_called_once_with(
+            'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
+
+    def test__is_share_valid_no_share_exist_exception(self):
+        fakeout = "mmlsfileset::allocInodes:"
+        self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._is_share_valid, self.fakedev,
+                          self.fakesharepath)
+
+        self._driver._gpfs_execute.assert_called_once_with(
+            'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
+
+    def test__get_share_name(self):
+        fakeout = "mmlsfileset::filesetName:\nmmlsfileset::existingshare:"
+        self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
+
+        result = self._driver._get_share_name(self.fakedev, self.fakesharepath)
+
+        self.assertEqual('existingshare', result)
+
+    def test__get_share_name_exception(self):
+        self._driver._gpfs_execute = mock.Mock(
+            side_effect=exception.ProcessExecutionError)
+
+        self.assertRaises(exception.ManageInvalidShare,
+                          self._driver._get_share_name, self.fakedev,
+                          self.fakesharepath)
+
+        self._driver._gpfs_execute.assert_called_once_with(
+            'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
+
+    def test__get_share_name_no_share_exist_exception(self):
+        fakeout = "mmlsfileset::filesetName:"
+        self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._get_share_name, self.fakedev,
+                          self.fakesharepath)
+
+        self._driver._gpfs_execute.assert_called_once_with(
+            'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
+
+    @ddt.data("mmlsquota::blockLimit:\nmmlsquota::1048577",
+              "mmlsquota::blockLimit:\nmmlsquota::1048576",
+              "mmlsquota::blockLimit:\nmmlsquota::0")
+    def test__manage_existing(self, fakeout):
+        self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
+        self._helper_fake.create_export.return_value = 'fakelocation'
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+
+        actual_size, actual_path = self._driver._manage_existing(
+            self.fakedev, self.share, self.fakeexistingshare)
+
+        self._driver._gpfs_execute.assert_any_call('mmunlinkfileset',
+                                                   self.fakedev,
+                                                   self.fakeexistingshare,
+                                                   '-f')
+        self._driver._gpfs_execute.assert_any_call('mmchfileset',
+                                                   self.fakedev,
+                                                   self.fakeexistingshare,
+                                                   '-j', self.share['name'])
+        self._driver._gpfs_execute.assert_any_call('mmlinkfileset',
+                                                   self.fakedev,
+                                                   self.share['name'],
+                                                   '-J', self.fakesharepath)
+        self._driver._gpfs_execute.assert_any_call('chmod',
+                                                   '777',
+                                                   self.fakesharepath)
+        if fakeout == "mmlsquota::blockLimit:\nmmlsquota::1048577":
+            self._driver._gpfs_execute.assert_called_with('mmsetquota',
+                                                          self.fakedev + ':' +
+                                                          self.share['name'],
+                                                          '--block',
+                                                          '0:2G')
+            self.assertEqual(2, actual_size)
+            self.assertEqual('fakelocation', actual_path)
+        elif fakeout == "mmlsquota::blockLimit:\nmmlsquota::0":
+            self._driver._gpfs_execute.assert_called_with('mmsetquota',
+                                                          self.fakedev + ':' +
+                                                          self.share['name'],
+                                                          '--block',
+                                                          '0:1G')
+            self.assertEqual(1, actual_size)
+            self.assertEqual('fakelocation', actual_path)
+        else:
+            self.assertEqual(1, actual_size)
+            self.assertEqual('fakelocation', actual_path)
+
+    def test__manage_existing_fileset_unlink_exception(self):
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self._driver._gpfs_execute = mock.Mock(
+            side_effect=exception.ProcessExecutionError)
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_called_once_with(self.share['name'])
+        self._driver._gpfs_execute.assert_called_once_with(
+            'mmunlinkfileset', self.fakedev, self.fakeexistingshare, '-f')
+
+    def test__manage_existing_fileset_creation_exception(self):
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
+            side_effect=['', exception.ProcessExecutionError]))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_any_call(self.share['name'])
+        self._driver._gpfs_execute.assert_has_calls([
+            mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
+                      '-f'),
+            mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
+                      '-j', self.share['name'])])
+
+    def test__manage_existing_fileset_relink_exception(self):
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
+            side_effect=['', '', exception.ProcessExecutionError]))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_any_call(self.share['name'])
+        self._driver._gpfs_execute.assert_has_calls([
+            mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
+                      '-f'),
+            mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
+                      '-j', self.share['name']),
+            mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
+                      self.fakesharepath)])
+
+    def test__manage_existing_permission_change_exception(self):
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
+            side_effect=['', '', '', exception.ProcessExecutionError]))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_any_call(self.share['name'])
+        self._driver._gpfs_execute.assert_has_calls([
+            mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
+                      '-f'),
+            mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
+                      '-j', self.share['name']),
+            mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
+                      self.fakesharepath),
+            mock.call('chmod', '777', self.fakesharepath)])
+
+    def test__manage_existing_checking_quota_of_fileset_exception(self):
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
+            side_effect=['', '', '', '', exception.ProcessExecutionError]))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_any_call(self.share['name'])
+        self._driver._gpfs_execute.assert_has_calls([
+            mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
+                      '-f'),
+            mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
+                      '-j', self.share['name']),
+            mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
+                      self.fakesharepath),
+            mock.call('chmod', '777', self.fakesharepath),
+            mock.call('mmlsquota', '-j', self.share['name'], '-Y',
+                      self.fakedev)])
+
+    def test__manage_existing_unable_to_get_quota_of_fileset_exception(self):
+        fakeout = "mmlsquota::blockLimit:"
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_any_call(self.share['name'])
+        self._driver._gpfs_execute.assert_any_call('mmunlinkfileset',
+                                                   self.fakedev,
+                                                   self.fakeexistingshare,
+                                                   '-f')
+        self._driver._gpfs_execute.assert_any_call('mmchfileset',
+                                                   self.fakedev,
+                                                   self.fakeexistingshare,
+                                                   '-j', self.share['name'])
+        self._driver._gpfs_execute.assert_any_call('mmlinkfileset',
+                                                   self.fakedev,
+                                                   self.share['name'],
+                                                   '-J', self.fakesharepath)
+        self._driver._gpfs_execute.assert_any_call('chmod',
+                                                   '777',
+                                                   self.fakesharepath)
+        self._driver._gpfs_execute.assert_called_with(
+            'mmlsquota', '-j', self.share['name'], '-Y', self.fakedev)
+
+    def test__manage_existing_set_quota_of_fileset_less_than_1G_exception(
+            self):
+        sizestr = '1G'
+        mock_out = "mmlsquota::blockLimit:\nmmlsquota::0:", None
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
+            side_effect=['', '', '', '', mock_out,
+                         exception.ProcessExecutionError]))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_any_call(self.share['name'])
+        self._driver._gpfs_execute.assert_has_calls([
+            mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
+                      '-f'),
+            mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
+                      '-j', self.share['name']),
+            mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
+                      self.fakesharepath),
+            mock.call('chmod', '777', self.fakesharepath),
+            mock.call('mmlsquota', '-j', self.share['name'], '-Y',
+                      self.fakedev),
+            mock.call('mmsetquota', self.fakedev + ':' + self.share['name'],
+                      '--block', '0:' + sizestr)])
+
+    def test__manage_existing_set_quota_of_fileset_grater_than_1G_exception(
+            self):
+        sizestr = '2G'
+        mock_out = "mmlsquota::blockLimit:\nmmlsquota::1048577:", None
+        self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
+        self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
+            side_effect=['', '', '', '', mock_out,
+                         exception.ProcessExecutionError]))
+
+        self.assertRaises(exception.GPFSException,
+                          self._driver._manage_existing, self.fakedev,
+                          self.share, self.fakeexistingshare)
+
+        self._driver._local_path.assert_any_call(self.share['name'])
+        self._driver._gpfs_execute.assert_has_calls([
+            mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
+                      '-f'),
+            mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
+                      '-j', self.share['name']),
+            mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
+                      self.fakesharepath),
+            mock.call('chmod', '777', self.fakesharepath),
+            mock.call('mmlsquota', '-j', self.share['name'], '-Y',
+                      self.fakedev),
+            mock.call('mmsetquota', self.fakedev + ':' + self.share['name'],
+                      '--block', '0:' + sizestr)])
+
+    def test_manage_existing(self):
+        self._driver._manage_existing = mock.Mock(return_value=('1',
+                                                  'fakelocation'))
+        self._driver._get_gpfs_device = mock.Mock(return_value=self.fakedev)
+        self._driver._is_share_valid = mock.Mock(return_value=True)
+        self._driver._get_share_name = mock.Mock(return_value=self.
+                                                 fakeexistingshare)
+        self._helper_fake._has_client_access = mock.Mock(return_value=[])
+
+        result = self._driver.manage_existing(self.share, {})
+
+        self.assertEqual('1', result['size'])
+        self.assertEqual('fakelocation', result['export_locations'])
+
+    def test_manage_existing_incorrect_path_exception(self):
+        share = fake_share.fake_share(export_location="wrong_ip::wrong_path")
+
+        self.assertRaises(exception.ShareBackendException,
+                          self._driver.manage_existing, share, {})
+
+    def test_manage_existing_incorrect_ip_exception(self):
+        share = fake_share.fake_share(export_location="wrong_ip:wrong_path")
+
+        self.assertRaises(exception.ShareBackendException,
+                          self._driver.manage_existing, share, {})
+
+    def test__manage_existing_invalid_export_exception(self):
+        share = fake_share.fake_share(export_location="wrong_ip/wrong_path")
+
+        self.assertRaises(exception.ShareBackendException,
+                          self._driver.manage_existing, share, {})
+
+    @ddt.data(True, False)
+    def test_manage_existing_invalid_share_exception(self, valid_share):
+        self._driver._get_gpfs_device = mock.Mock(return_value=self.fakedev)
+        self._driver._is_share_valid = mock.Mock(return_value=valid_share)
+        if valid_share:
+            self._driver._get_share_name = mock.Mock(return_value=self.
+                                                     fakeexistingshare)
+            self._helper_fake._has_client_access = mock.Mock()
+        else:
+            self.assertFalse(self._helper_fake._has_client_access.called)
+
+        self.assertRaises(exception.ManageInvalidShare,
+                          self._driver.manage_existing, self.share, {})
+
     def test__gpfs_local_execute(self):
         self.mock_object(utils, 'execute', mock.Mock(return_value=True))
         cmd = "testcmd"
@@ -730,6 +1061,28 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
                           self._knfs_helper.get_export_options,
                           share, access, 'KNFS', options_not_allowed)
 
+    @ddt.data(("/gpfs0/share-fakeid\t10.0.0.1", None),
+              ("", None),
+              ("/gpfs0/share-fakeid\t10.0.0.1", "10.0.0.1"),
+              ("/gpfs0/share-fakeid\t10.0.0.1", "10.0.0.2"))
+    @ddt.unpack
+    def test_knfs__has_client_access(self, mock_out, access_to):
+        self._knfs_helper._execute = mock.Mock(return_value=[mock_out, 0])
+
+        result = self._knfs_helper._has_client_access(self.fakesharepath,
+                                                      access_to)
+
+        self._ces_helper._execute.assert_called_once_with('exportfs',
+                                                          check_exit_code=True,
+                                                          run_as_root=True)
+        if mock_out == "/gpfs0/share-fakeid\t10.0.0.1":
+            if access_to in (None, "10.0.0.1"):
+                self.assertTrue(result)
+            else:
+                self.assertFalse(result)
+        else:
+            self.assertFalse(result)
+
     def test_knfs_allow_access(self):
         self._knfs_helper._execute = mock.Mock(
             return_value=['/fs0 <world>', 0]
@@ -1041,7 +1394,8 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
         access = self.access
         local_path = self.fakesharepath
 
-        self._ces_helper.allow_access(local_path, self.share, access)
+        self._ces_helper.allow_access(self.fakesharepath, self.share,
+                                      self.access)
 
         self._ces_helper._execute.assert_has_calls([
             mock.call('mmnfs', 'export', 'list', '-n', local_path, '-Y'),
diff --git a/releasenotes/notes/ibm-gpfs-manage-support-c110120c350728e3.yaml b/releasenotes/notes/ibm-gpfs-manage-support-c110120c350728e3.yaml
new file mode 100644
index 0000000000..086cd07434
--- /dev/null
+++ b/releasenotes/notes/ibm-gpfs-manage-support-c110120c350728e3.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - Added manila manage/unmanage feature support for
+    GPFS driver.
+    The existing fileset should be an independent fileset
+    and should not have any NFS export over the fileset
+    path. With this prerequisite existing GPFS filesets
+    can be brought under Manila management.