From 266972ab91742c875362596afcef2ebb47f38189 Mon Sep 17 00:00:00 2001
From: "Kuirong.Chen" <Kuirong.Chen@infortrend.com>
Date: Wed, 8 May 2019 18:43:32 +0800
Subject: [PATCH] Add Infortrend Manila Driver

This driver supports NFS and CIFS shares.

The following operations are supported:
 - Create a share.
 - Delete a share.
 - Allow share access.
 - Deny share access.
 - Manage a share.
 - Unmanage a share.
 - Extend a share.
 - Shrink a share.

DocImpact
Implements: blueprint infortrend-support-manila-driver

Change-Id: Ib1adbd8f7f55805387b126851dbb0ff50cfbcd75
---
 ...hare_back_ends_feature_support_mapping.rst |   8 +
 manila/exception.py                           |  10 +
 manila/opts.py                                |   2 +
 manila/share/drivers/infortrend/__init__.py   |   0
 manila/share/drivers/infortrend/driver.py     | 257 +++++++
 .../drivers/infortrend/infortrend_nas.py      | 642 ++++++++++++++++++
 manila/tests/conf_fixture.py                  |   4 +
 .../share/drivers/infortrend/__init__.py      |   0
 .../infortrend/fake_infortrend_manila_data.py | 408 +++++++++++
 .../infortrend/fake_infortrend_nas_data.py    | 416 ++++++++++++
 .../drivers/infortrend/test_infortrend_nas.py | 573 ++++++++++++++++
 ...rtrend-manila-driver-a1a2af20de6368cb.yaml |   5 +
 12 files changed, 2325 insertions(+)
 create mode 100644 manila/share/drivers/infortrend/__init__.py
 create mode 100644 manila/share/drivers/infortrend/driver.py
 create mode 100644 manila/share/drivers/infortrend/infortrend_nas.py
 create mode 100644 manila/tests/share/drivers/infortrend/__init__.py
 create mode 100644 manila/tests/share/drivers/infortrend/fake_infortrend_manila_data.py
 create mode 100644 manila/tests/share/drivers/infortrend/fake_infortrend_nas_data.py
 create mode 100644 manila/tests/share/drivers/infortrend/test_infortrend_nas.py
 create mode 100644 releasenotes/notes/infortrend-manila-driver-a1a2af20de6368cb.yaml

diff --git a/doc/source/admin/share_back_ends_feature_support_mapping.rst b/doc/source/admin/share_back_ends_feature_support_mapping.rst
index c46ed45f6b..eef78c3c2c 100644
--- a/doc/source/admin/share_back_ends_feature_support_mapping.rst
+++ b/doc/source/admin/share_back_ends_feature_support_mapping.rst
@@ -71,6 +71,8 @@ Mapping of share drivers and share features support
 +----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+--------------------+--------------------+
 |            INSPUR InStorage            |           T           |          \-           |       T      |      \-      |           \-           |             \-             |            \-            |           \-       |           \-       |
 +----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+--------------------+--------------------+
+|               Infortrend               |           T           |           T           |       T      |       T      |            \-          |             \-             |            \-            |          \-        |          \-        |
++----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+--------------------+--------------------+
 |                  LVM                   |           M           |          \-           |       M      |      \-      |            M           |              M             |            \-            |           O        |           O        |
 +----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+--------------------+--------------------+
 |                Quobyte                 |           K           |          \-           |       M      |       M      |           \-           |             \-             |            \-            |          \-        |          \-        |
@@ -144,6 +146,8 @@ Mapping of share drivers and share access rules support
 +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
 |            INSPUR InStorage            |    NFS (T)   |      \-      |    CIFS (T)    |     \-     |      \-      |    NFS (T)   |      \-      |    CIFS (T)    |     \-     |     \-     |
 +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
+|               Infortrend               |    NFS (T)   |      \-      |    CIFS (T)    |     \-     |      \-      |    NFS (T)   |      \-      |    CIFS (T)    |     \-     |     \-     |
++----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
 |              Oracle ZFSSA              |  NFS,CIFS(K) |      \-      |       \-       |     \-     |      \-      |      \-      |      \-      |       \-       |     \-     |     \-     |
 +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
 |                 CephFS                 |    NFS (P)   |      \-      |       \-       |     \-     |  CEPHFS (M)  |    NFS (P)   |      \-      |       \-       |     \-     | CEPHFS (N) |
@@ -209,6 +213,8 @@ Mapping of share drivers and security services support
 +----------------------------------------+------------------+-----------------+------------------+
 |            INSPUR InStorage            |        \-        |         \-      |        \-        |
 +----------------------------------------+------------------+-----------------+------------------+
+|               Infortrend               |        \-        |         \-      |        \-        |
++----------------------------------------+------------------+-----------------+------------------+
 |              Oracle ZFSSA              |        \-        |        \-       |        \-        |
 +----------------------------------------+------------------+-----------------+------------------+
 |                CephFS                  |        \-        |        \-       |        \-        |
@@ -264,6 +270,8 @@ More information: :ref:`capabilities_and_extra_specs`
 +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
 |                INFINIDAT               |     \-    |      Q     |   \-   |      \-     |         Q         |          Q         | \-  |              Q             |          Q         |           Q        |       Q      |      \-      |
 +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
+|               Infortrend               |     \-    |      T     |   \-   |      \-     |        \-         |          \-        | \-  |             \-             |          \-        |          \-        |       T      |      \-      |
++----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
 |                   LVM                  |     \-    |      M     |   \-   |      \-     |        \-         |          M         | \-  |              K             |          O         |           O        |       P      |      P       |
 +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
 |                Quobyte                 |     \-    |      K     |   \-   |      \-     |        \-         |          L         | \-  |              M             |          \-        |          \-        |       P      |      \-      |
diff --git a/manila/exception.py b/manila/exception.py
index 11e8a9684a..94297204de 100644
--- a/manila/exception.py
+++ b/manila/exception.py
@@ -967,3 +967,13 @@ class LockingFailed(ManilaException):
 # Ganesha library
 class GaneshaException(ManilaException):
     message = _("Unknown NFS-Ganesha library exception.")
+
+
+# Infortrend Storage driver
+class InfortrendCLIException(ShareBackendException):
+    message = _("Infortrend CLI exception: %(err)s "
+                "Return Code: %(rc)s, Output: %(out)s")
+
+
+class InfortrendNASException(ShareBackendException):
+    message = _("Infortrend NAS exception: %(err)s")
diff --git a/manila/opts.py b/manila/opts.py
index b41e7c161c..b83d531ad7 100644
--- a/manila/opts.py
+++ b/manila/opts.py
@@ -72,6 +72,7 @@ import manila.share.drivers.hpe.hpe_3par_driver
 import manila.share.drivers.huawei.huawei_nas
 import manila.share.drivers.ibm.gpfs
 import manila.share.drivers.infinidat.infinibox
+import manila.share.drivers.infortrend.driver
 import manila.share.drivers.inspur.as13000.as13000_nas
 import manila.share.drivers.inspur.instorage.instorage
 import manila.share.drivers.lvm
@@ -159,6 +160,7 @@ _global_opt_lists = [
     manila.share.drivers.infinidat.infinibox.infinidat_auth_opts,
     manila.share.drivers.infinidat.infinibox.infinidat_connection_opts,
     manila.share.drivers.infinidat.infinibox.infinidat_general_opts,
+    manila.share.drivers.infortrend.driver.infortrend_nas_opts,
     manila.share.drivers.inspur.as13000.as13000_nas.inspur_as13000_opts,
     manila.share.drivers.inspur.instorage.instorage.instorage_opts,
     manila.share.drivers.maprfs.maprfs_native.maprfs_native_share_opts,
diff --git a/manila/share/drivers/infortrend/__init__.py b/manila/share/drivers/infortrend/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/manila/share/drivers/infortrend/driver.py b/manila/share/drivers/infortrend/driver.py
new file mode 100644
index 0000000000..064f31f6e2
--- /dev/null
+++ b/manila/share/drivers/infortrend/driver.py
@@ -0,0 +1,257 @@
+# Copyright (c) 2019 Infortrend Technology, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from oslo_config import cfg
+from oslo_log import log
+
+from manila import exception
+from manila.i18n import _
+from manila.share import driver
+from manila.share.drivers.infortrend import infortrend_nas
+
+LOG = log.getLogger(__name__)
+
+infortrend_nas_opts = [
+    cfg.HostAddressOpt('infortrend_nas_ip',
+                       required=True,
+                       help='Infortrend NAS IP for management.'),
+    cfg.StrOpt('infortrend_nas_user',
+               default='manila',
+               help='User for the Infortrend NAS server.'),
+    cfg.StrOpt('infortrend_nas_password',
+               default=None,
+               secret=True,
+               help='Password for the Infortrend NAS server. '
+               'This is not necessary '
+               'if infortrend_nas_ssh_key is set.'),
+    cfg.StrOpt('infortrend_nas_ssh_key',
+               default=None,
+               help='SSH key for the Infortrend NAS server. '
+               'This is not necessary '
+               'if infortrend_nas_password is set.'),
+    cfg.ListOpt('infortrend_share_pools',
+                required=True,
+                help='Comma separated list of Infortrend NAS pools.'),
+    cfg.ListOpt('infortrend_share_channels',
+                required=True,
+                help='Comma separated list of Infortrend channels.'),
+    cfg.IntOpt('infortrend_ssh_timeout',
+               default=30,
+               help='SSH timeout in seconds.'),
+]
+
+CONF = cfg.CONF
+CONF.register_opts(infortrend_nas_opts)
+
+
+class InfortrendNASDriver(driver.ShareDriver):
+
+    """Infortrend Share Driver for GS/GSe Family using NASCLI.
+
+    Version history:
+        1.0.0 - Initial driver
+    """
+
+    VERSION = "1.0.0"
+    PROTOCOL = "NFS_CIFS"
+
+    def __init__(self, *args, **kwargs):
+        super(InfortrendNASDriver, self).__init__(False, *args, **kwargs)
+        self.configuration.append_config_values(infortrend_nas_opts)
+
+        nas_ip = self.configuration.safe_get('infortrend_nas_ip')
+        username = self.configuration.safe_get('infortrend_nas_user')
+        password = self.configuration.safe_get('infortrend_nas_password')
+        ssh_key = self.configuration.safe_get('infortrend_nas_ssh_key')
+        timeout = self.configuration.safe_get('infortrend_ssh_timeout')
+        self.backend_name = self.configuration.safe_get('share_backend_name')
+
+        if not (password or ssh_key):
+            msg = _('Either infortrend_nas_password or infortrend_nas_ssh_key '
+                    'should be set.')
+            raise exception.InvalidParameterValue(err=msg)
+
+        pool_dict = self._init_pool_dict()
+        channel_dict = self._init_channel_dict()
+        self.ift_nas = infortrend_nas.InfortrendNAS(nas_ip, username, password,
+                                                    ssh_key, timeout,
+                                                    pool_dict, channel_dict)
+
+    def _init_pool_dict(self):
+        pools_names = self.configuration.safe_get('infortrend_share_pools')
+
+        return {el: {} for el in pools_names}
+
+    def _init_channel_dict(self):
+        channels = self.configuration.safe_get('infortrend_share_channels')
+
+        return {el: '' for el in channels}
+
+    def do_setup(self, context):
+        """Any initialization the share driver does while starting."""
+        LOG.debug('Infortrend NAS do_setup start.')
+        self.ift_nas.do_setup()
+
+    def check_for_setup_error(self):
+        """Check for setup error."""
+        LOG.debug('Infortrend NAS check_for_setup_error start.')
+        self.ift_nas.check_for_setup_error()
+
+    def _update_share_stats(self):
+        """Retrieve stats info from share group."""
+
+        LOG.debug('Updating Infortrend backend [%s].', self.backend_name)
+
+        data = dict(
+            share_backend_name=self.backend_name,
+            vendor_name='Infortrend',
+            driver_version=self.VERSION,
+            storage_protocol=self.PROTOCOL,
+            reserved_percentage=self.configuration.reserved_share_percentage,
+            pools=self.ift_nas.update_pools_stats())
+        LOG.debug('Infortrend pools status: %s', data['pools'])
+
+        super(InfortrendNASDriver, self)._update_share_stats(data)
+
+    def update_access(self, context, share, access_rules, add_rules,
+                      delete_rules, share_server=None):
+        """Update access rules for given share.
+
+        :param context: Current context
+        :param share: Share model with share data.
+        :param access_rules: All access rules for given share
+        :param add_rules: Empty List or List of access rules which should be
+               added. access_rules already contains these rules.
+        :param delete_rules: Empty List or List of access rules which should be
+               removed. access_rules doesn't contain these rules.
+        :param share_server: Not used by this driver.
+
+        :returns: None, or a dictionary of ``access_id``, ``access_key`` as
+                  key: value pairs for the rules added, where, ``access_id``
+                  is the UUID (string) of the access rule, and ``access_key``
+                  is the credential (string) of the entity granted access.
+                  During recovery after error, the returned dictionary must
+                  contain ``access_id``, ``access_key`` for all the rules that
+                  the driver is ordered to resync, i.e. rules in the
+                  ``access_rules`` parameter.
+        """
+
+        return self.ift_nas.update_access(share, access_rules, add_rules,
+                                          delete_rules, share_server)
+
+    def create_share(self, context, share, share_server=None):
+        """Create a share."""
+
+        LOG.debug('Creating share: %s.', share['id'])
+
+        return self.ift_nas.create_share(share, share_server)
+
+    def delete_share(self, context, share, share_server=None):
+        """Remove a share."""
+
+        LOG.debug('Deleting share: %s.', share['id'])
+
+        return self.ift_nas.delete_share(share, share_server)
+
+    def get_pool(self, share):
+        """Return pool name where the share resides on.
+
+        :param share: The share hosted by the driver.
+        """
+        return self.ift_nas.get_pool(share)
+
+    def ensure_share(self, context, share, share_server=None):
+        """Invoked to ensure that share is exported.
+
+        Driver can use this method to update the list of export locations of
+        the share if it changes. To do that, you should return list with
+        export locations.
+
+        :return None or list with export locations
+        """
+        return self.ift_nas.ensure_share(share, share_server)
+
+    def manage_existing(self, share, driver_options):
+        """Brings an existing share under Manila management.
+
+        If the provided share is not valid, then raise a
+        ManageInvalidShare exception, specifying a reason for the failure.
+
+        If the provided share is not in a state that can be managed, such as
+        being replicated on the backend, the driver *MUST* raise
+        ManageInvalidShare exception with an appropriate message.
+
+        The share has a share_type, and the driver can inspect that and
+        compare against the properties of the referenced backend share.
+        If they are incompatible, raise a
+        ManageExistingShareTypeMismatch, specifying a reason for the failure.
+
+        :param share: Share model
+        :param driver_options: Driver-specific options provided by admin.
+        :return: share_update dictionary with required key 'size',
+                 which should contain size of the share.
+        """
+        LOG.debug(
+            'Manage existing for share: %(share)s,', {
+                'share': share['share_id'],
+            })
+        return self.ift_nas.manage_existing(share, driver_options)
+
+    def unmanage(self, share):
+        """Removes the specified share from Manila management.
+
+        Does not delete the underlying backend share.
+
+        For most drivers, this will not need to do anything.  However, some
+        drivers might use this call as an opportunity to clean up any
+        Manila-specific configuration that they have associated with the
+        backend share.
+
+        If provided share cannot be unmanaged, then raise an
+        UnmanageInvalidShare exception, specifying a reason for the failure.
+
+        This method is invoked when the share is being unmanaged with
+        a share type that has ``driver_handles_share_servers``
+        extra-spec set to False.
+        """
+        LOG.debug(
+            'Unmanage share: %(share)s', {
+                'share': share['share_id'],
+            })
+        return self.ift_nas.unmanage(share)
+
+    def extend_share(self, share, new_size, share_server=None):
+        """Extends size of existing share.
+
+        :param share: Share model
+        :param new_size: New size of share (new_size > share['size'])
+        :param share_server: Optional -- Share server model
+        """
+        return self.ift_nas.extend_share(share, new_size, share_server)
+
+    def shrink_share(self, share, new_size, share_server=None):
+        """Shrinks size of existing share.
+
+        If consumed space on share larger than new_size driver should raise
+        ShareShrinkingPossibleDataLoss exception:
+        raise ShareShrinkingPossibleDataLoss(share_id=share['id'])
+
+        :param share: Share model
+        :param new_size: New size of share (new_size < share['size'])
+        :param share_server: Optional -- Share server model
+
+        :raises ShareShrinkingPossibleDataLoss, NotImplementedError
+        """
+        return self.ift_nas.shrink_share(share, new_size, share_server)
diff --git a/manila/share/drivers/infortrend/infortrend_nas.py b/manila/share/drivers/infortrend/infortrend_nas.py
new file mode 100644
index 0000000000..1167286447
--- /dev/null
+++ b/manila/share/drivers/infortrend/infortrend_nas.py
@@ -0,0 +1,642 @@
+# Copyright (c) 2019 Infortrend Technology, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+import re
+
+from oslo_concurrency import processutils
+from oslo_log import log
+from oslo_utils import units
+
+from manila.common import constants
+from manila import exception
+from manila.i18n import _
+from manila.share import utils as share_utils
+from manila import utils as manila_utils
+
+LOG = log.getLogger(__name__)
+
+
+def _bi_to_gi(bi_size):
+    return bi_size / units.Gi
+
+
+class InfortrendNAS(object):
+
+    _SSH_PORT = 22
+
+    def __init__(self, nas_ip, username, password, ssh_key,
+                 timeout, pool_dict, channel_dict):
+        self.nas_ip = nas_ip
+        self.port = self._SSH_PORT
+        self.username = username
+        self.password = password
+        self.ssh_key = ssh_key
+        self.ssh_timeout = timeout
+        self.pool_dict = pool_dict
+        self.channel_dict = channel_dict
+        self.command = ""
+        self.ssh = None
+        self.sshpool = None
+        self.location = 'a@0'
+
+    def _execute(self, command_line):
+        command_line.extend(['-z', self.location])
+        commands = ' '.join(command_line)
+        manila_utils.check_ssh_injection(commands)
+        LOG.debug('Executing: %(command)s', {'command': commands})
+
+        cli_out = self._ssh_execute(commands)
+
+        return self._parser(cli_out)
+
+    def _ssh_execute(self, commands):
+        try:
+            out, err = processutils.ssh_execute(
+                self.ssh, commands,
+                timeout=self.ssh_timeout, check_exit_code=True)
+        except processutils.ProcessExecutionError as pe:
+            rc = pe.exit_code
+            out = pe.stdout
+            out = out.replace('\n', '\\n')
+            msg = _('Error on execute ssh command. '
+                    'Exit code: %(rc)d, msg: %(out)s') % {
+                        'rc': rc, 'out': out}
+            raise exception.InfortrendNASException(err=msg)
+
+        return out
+
+    def _parser(self, content=None):
+        LOG.debug('parsing data:\n%s', content)
+        content = content.replace("\r", "")
+        content = content.strip()
+        json_string = content.replace("'", "\"")
+        cli_data = json_string.splitlines()[2]
+        if cli_data:
+            try:
+                data_dict = json.loads(cli_data)
+            except Exception:
+                msg = _('Failed to parse data: '
+                        '%(cli_data)s to dictionary.') % {
+                            'cli_data': cli_data}
+                LOG.error(msg)
+                raise exception.InfortrendNASException(err=msg)
+
+            rc = int(data_dict['cliCode'][0]['Return'], 16)
+            if rc == 0:
+                result = data_dict['data']
+            else:
+                result = data_dict['cliCode'][0]['CLI']
+        else:
+            msg = _('No data is returned from NAS.')
+            LOG.error(msg)
+            raise exception.InfortrendNASException(err=msg)
+
+        if rc != 0:
+            msg = _('NASCLI error, returned: %(result)s.') % {
+                'result': result}
+            LOG.error(msg)
+            raise exception.InfortrendCLIException(
+                err=msg, rc=rc, out=result)
+
+        return rc, result
+
+    def do_setup(self):
+        self._init_connect()
+        self._ensure_service_on('nfs')
+        self._ensure_service_on('cifs')
+
+    def _init_connect(self):
+        if not (self.sshpool and self.ssh):
+            self.sshpool = manila_utils.SSHPool(ip=self.nas_ip,
+                                                port=self.port,
+                                                conn_timeout=None,
+                                                login=self.username,
+                                                password=self.password,
+                                                privatekey=self.ssh_key)
+            self.ssh = self.sshpool.create()
+
+        if not self.ssh.get_transport().is_active():
+            self.sshpool = manila_utils.SSHPool(ip=self.nas_ip,
+                                                port=self.port,
+                                                conn_timeout=None,
+                                                login=self.username,
+                                                password=self.password,
+                                                privatekey=self.ssh_key)
+            self.ssh = self.sshpool.create()
+
+        LOG.debug('NAScmd [%s@%s] start!', self.username, self.nas_ip)
+
+    def check_for_setup_error(self):
+        self._check_pools_setup()
+        self._check_channels_status()
+
+    def _ensure_service_on(self, proto, slot='A'):
+        command_line = ['service', 'status', proto]
+        rc, service_status = self._execute(command_line)
+        if not service_status[0][slot][proto.upper()]['enabled']:
+            command_line = ['service', 'restart', proto]
+            self._execute(command_line)
+
+    def _check_channels_status(self):
+        channel_list = list(self.channel_dict.keys())
+        command_line = ['ifconfig', 'inet', 'show']
+        rc, channels_status = self._execute(command_line)
+        for channel in channels_status:
+            if 'CH' in channel['datalink']:
+                ch = channel['datalink'].strip('CH')
+                if ch in self.channel_dict.keys():
+                    self.channel_dict[ch] = channel['IP']
+                    channel_list.remove(ch)
+                    if channel['status'] == 'DOWN':
+                        LOG.warning('Channel [%(ch)s] status '
+                                    'is down, please check.', {
+                                        'ch': ch})
+        if len(channel_list) != 0:
+            msg = _('Channel setting %(channel_list)s is invalid!') % {
+                'channel_list': channel_list}
+            LOG.error(msg)
+            raise exception.InfortrendNASException(message=msg)
+
+    def _check_pools_setup(self):
+        pool_list = list(self.pool_dict.keys())
+        command_line = ['folder', 'status']
+        rc, pool_data = self._execute(command_line)
+        for pool in pool_data:
+            pool_name = self._extract_pool_name(pool)
+            if pool_name in self.pool_dict.keys():
+                pool_list.remove(pool_name)
+                self.pool_dict[pool_name]['id'] = pool['volumeId']
+                self.pool_dict[pool_name]['path'] = pool['directory'] + '/'
+            if len(pool_list) == 0:
+                break
+
+        if len(pool_list) != 0:
+            msg = _('Please create %(pool_list)s pool/s in advance!') % {
+                'pool_list': pool_list}
+            LOG.error(msg)
+            raise exception.InfortrendNASException(message=msg)
+
+    def _extract_pool_name(self, pool_info):
+        return pool_info['directory'].split('/')[1]
+
+    def _extract_lv_name(self, pool_info):
+        return pool_info['path'].split('/')[2]
+
+    def update_pools_stats(self):
+        pools = []
+        command_line = ['folder', 'status']
+        rc, pools_data = self._execute(command_line)
+
+        for pool_info in pools_data:
+            pool_name = self._extract_pool_name(pool_info)
+
+            if pool_name in self.pool_dict.keys():
+                total_space = float(pool_info['size'])
+                pool_quota_used = self._get_pool_quota_used(pool_name)
+                available_space = total_space - pool_quota_used
+
+                total_capacity_gb = round(_bi_to_gi(total_space), 2)
+                free_capacity_gb = round(_bi_to_gi(available_space), 2)
+
+                pool = {
+                    'pool_name': pool_name,
+                    'total_capacity_gb': total_capacity_gb,
+                    'free_capacity_gb': free_capacity_gb,
+                    'reserved_percentage': 0,
+                    'qos': False,
+                    'dedupe': False,
+                    'compression': False,
+                    'snapshot_support': False,
+                    'thin_provisioning': False,
+                    'thick_provisioning': True,
+                    'replication_type': None,
+                }
+                pools.append(pool)
+
+        return pools
+
+    def _get_pool_quota_used(self, pool_name):
+        pool_quota_used = 0.0
+        pool_data = self._get_share_pool_data(pool_name)
+        folder_name = self._extract_lv_name(pool_data)
+
+        command_line = ['fquota', 'status', pool_data['id'],
+                        folder_name, '-t', 'folder']
+        rc, quota_status = self._execute(command_line)
+
+        for share_quota in quota_status:
+            pool_quota_used += int(share_quota['quota'])
+
+        return pool_quota_used
+
+    def _get_share_pool_data(self, pool_name):
+        if not pool_name:
+            msg = _("Pool is not available in the share host.")
+            raise exception.InvalidHost(reason=msg)
+
+        if pool_name in self.pool_dict.keys():
+            return self.pool_dict[pool_name]
+        else:
+            msg = _('Pool [%(pool_name)s] not set in conf.') % {
+                'pool_name': pool_name}
+            LOG.error(msg)
+            raise exception.InfortrendNASException(err=msg)
+
+    def create_share(self, share, share_server=None):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        folder_name = self._extract_lv_name(pool_data)
+        share_proto = share['share_proto'].lower()
+        share_name = share['id'].replace('-', '')
+        share_path = pool_data['path'] + share_name
+
+        command_line = ['folder', 'options', pool_data['id'],
+                        folder_name, '-c', share_name]
+        self._execute(command_line)
+
+        self._set_share_size(
+            pool_data['id'], pool_name, share_name, share['size'])
+        self._ensure_protocol_on(share_path, share_proto, share_name)
+
+        LOG.info('Create Share [%(share)s] completed.', {
+            'share': share['id']})
+
+        return self._export_location(
+            share_name, share_proto, pool_data['path'])
+
+    def _export_location(self, share_name, share_proto, pool_path=None):
+        location = []
+        location_data = {
+            'pool_path': pool_path,
+            'share_name': share_name,
+        }
+        self._check_channels_status()
+        for ch in sorted(self.channel_dict.keys()):
+            ip = self.channel_dict[ch]
+            if share_proto == 'nfs':
+                location.append(
+                    ip + ':%(pool_path)s%(share_name)s' % location_data)
+            elif share_proto == 'cifs':
+                location.append(
+                    '\\\\' + ip + '\\%(share_name)s' % location_data)
+            else:
+                msg = _('Unsupported protocol: [%s].') % share_proto
+                raise exception.InvalidInput(msg)
+
+        return location
+
+    def _set_share_size(self, pool_id, pool_name, share_name, share_size):
+        pool_data = self._get_share_pool_data(pool_name)
+        folder_name = self._extract_lv_name(pool_data)
+        command_line = ['fquota', 'create', pool_id, folder_name,
+                        share_name, str(share_size) + 'G', '-t', 'folder']
+        self._execute(command_line)
+
+        LOG.debug('Set Share [%(share_name)s] '
+                  'Size [%(share_size)s G] completed.', {
+                      'share_name': share_name,
+                      'share_size': share_size})
+        return
+
+    def _get_share_size(self, pool_id, pool_name, share_name):
+        share_size = None
+        command_line = ['fquota', 'status', pool_id,
+                        share_name, '-t', 'folder']
+        rc, quota_status = self._execute(command_line)
+
+        for share_quota in quota_status:
+            if share_quota['name'] == share_name:
+                share_size = round(_bi_to_gi(float(share_quota['quota'])), 2)
+                break
+
+        return share_size
+
+    def delete_share(self, share, share_server=None):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        folder_name = self._extract_lv_name(pool_data)
+        share_name = share['id'].replace('-', '')
+
+        if self._check_share_exist(pool_name, share_name):
+            command_line = ['folder', 'options', pool_data['id'],
+                            folder_name, '-d', share_name]
+            self._execute(command_line)
+        else:
+            LOG.warning('Share [%(share_name)s] is already deleted.', {
+                'share_name': share_name})
+
+        LOG.info('Delete Share [%(share)s] completed.', {
+            'share': share['id']})
+
+    def _check_share_exist(self, pool_name, share_name):
+        path = self.pool_dict[pool_name]['path']
+        command_line = ['pagelist', 'folder', path]
+        rc, subfolders = self._execute(command_line)
+        return any(subfolder['name'] == share_name for subfolder in subfolders)
+
+    def update_access(self, share, access_rules, add_rules,
+                      delete_rules, share_server=None):
+        self._evict_unauthorized_clients(share, access_rules, share_server)
+        access_dict = {}
+        for access in access_rules:
+            try:
+                self._allow_access(share, access, share_server)
+            except (exception.InfortrendNASException) as e:
+                msg = _('Failed to allow access to client %(access)s, '
+                        'reason %(e)s.') % {
+                            'access': access['access_to'], 'e': e}
+                LOG.error(msg)
+                access_dict[access['id']] = 'error'
+
+        return access_dict
+
+    def _evict_unauthorized_clients(self, share, access_rules,
+                                    share_server=None):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        share_proto = share['share_proto'].lower()
+        share_name = share['id'].replace('-', '')
+        share_path = pool_data['path'] + share_name
+
+        access_list = []
+        for access in access_rules:
+            access_list.append(access['access_to'])
+
+        if share_proto == 'nfs':
+            host_ip_list = []
+            command_line = ['share', 'status', '-f', share_path]
+            rc, nfs_status = self._execute(command_line)
+            host_list = nfs_status[0]['nfs_detail']['hostList']
+            for host in host_list:
+                if host['host'] != '*':
+                    host_ip_list.append(host['host'])
+            for ip in host_ip_list:
+                if ip not in access_list:
+                    command_line = ['share', 'options', share_path,
+                                    'nfs', '-c', ip]
+                    try:
+                        self._execute(command_line)
+                    except exception.InfortrendNASException:
+                        msg = _("Failed to remove share access rule %s") % (ip)
+                        LOG.exception(msg)
+                        pass
+
+        elif share_proto == 'cifs':
+            host_user_list = []
+            command_line = ['acl', 'get', share_path]
+            rc, cifs_status = self._execute(command_line)
+            for cifs_rule in cifs_status:
+                if cifs_rule['name']:
+                    host_user_list.append(cifs_rule['name'])
+            for user in host_user_list:
+                if user not in access_list:
+                    command_line = ['acl', 'delete', share_path, '-u', user]
+                    try:
+                        self._execute(command_line)
+                    except exception.InfortrendNASException:
+                        msg = _("Failed to remove share access rule %s") % (
+                            user)
+                        LOG.exception(msg)
+                        pass
+
+    def _allow_access(self, share, access, share_server=None):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        share_name = share['id'].replace('-', '')
+        share_path = pool_data['path'] + share_name
+        share_proto = share['share_proto'].lower()
+        access_type = access['access_type']
+        access_level = access['access_level'] or constants.ACCESS_LEVEL_RW
+        access_to = access['access_to']
+        ACCESS_LEVEL_MAP = {access_level: access_level}
+        msg = self._check_access_legal(share_proto, access_type)
+        if msg:
+            raise exception.InvalidShareAccess(reason=msg)
+
+        if share_proto == 'nfs':
+            command_line = ['share', 'options', share_path, 'nfs',
+                            '-h', access_to, '-p', access_level]
+            self._execute(command_line)
+
+        elif share_proto == 'cifs':
+            if not self._check_user_exist(access_to):
+                msg = _('Please create user [%(user)s] in advance.') % {
+                    'user': access_to}
+                LOG.error(msg)
+                raise exception.InfortrendNASException(err=msg)
+
+            if access_level == constants.ACCESS_LEVEL_RW:
+                cifs_access = 'f'
+            elif access_level == constants.ACCESS_LEVEL_RO:
+                cifs_access = 'r'
+            try:
+                access_level = ACCESS_LEVEL_MAP[access_level]
+            except KeyError:
+                msg = _('Unsupported access_level: [%s].') % access_level
+                raise exception.InvalidInput(msg)
+
+            command_line = ['acl', 'set', share_path,
+                            '-u', access_to, '-a', cifs_access]
+            self._execute(command_line)
+
+        LOG.info('Share [%(share)s] access to [%(access_to)s] '
+                 'level [%(level)s] protocol [%(share_proto)s] completed.', {
+                     'share': share['id'],
+                     'access_to': access_to,
+                     'level': access_level,
+                     'share_proto': share_proto})
+
+    def _ensure_protocol_on(self, share_path, share_proto, cifs_name):
+        if not self._check_proto_enabled(share_path, share_proto):
+            command_line = ['share', share_path, share_proto, 'on']
+            if share_proto == 'cifs':
+                command_line.extend(['-n', cifs_name])
+            self._execute(command_line)
+
+    def _check_proto_enabled(self, share_path, share_proto):
+        command_line = ['share', 'status', '-f', share_path]
+        rc, share_status = self._execute(command_line)
+        if share_status:
+            check_enabled = share_status[0][share_proto]
+            if check_enabled:
+                return True
+        return False
+
+    def _check_user_exist(self, user_name):
+        command_line = ['useradmin', 'user', 'list']
+        rc, user_list = self._execute(command_line)
+        for user in user_list:
+            if user['Name'] == user_name:
+                return True
+        return False
+
+    def _check_access_legal(self, share_proto, access_type):
+        msg = None
+        if share_proto == 'cifs' and access_type != 'user':
+            msg = _('Infortrend CIFS share only supports USER access type.')
+        elif share_proto == 'nfs' and access_type != 'ip':
+            msg = _('Infortrend NFS share only supports IP access type.')
+        elif share_proto not in ('nfs', 'cifs'):
+            msg = _('Unsupported share protocol [%s].') % share_proto
+        return msg
+
+    def get_pool(self, share):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        if not pool_name:
+            share_name = share['id'].replace('-', '')
+            for pool in self.pool_dict.keys():
+                if self._check_share_exist(pool, share_name):
+                    pool_name = pool
+                    break
+        return pool_name
+
+    def ensure_share(self, share, share_server=None):
+        share_proto = share['share_proto'].lower()
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        share_name = share['id'].replace('-', '')
+        return self._export_location(
+            share_name, share_proto, pool_data['path'])
+
+    def extend_share(self, share, new_size, share_server=None):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        share_name = share['id'].replace('-', '')
+        self._set_share_size(pool_data['id'], pool_name, share_name, new_size)
+
+        LOG.info('Successfully Extend Share [%(share)s] '
+                 'to size [%(new_size)s G].', {
+                     'share': share['id'],
+                     'new_size': new_size})
+
+    def shrink_share(self, share, new_size, share_server=None):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        share_name = share['id'].replace('-', '')
+        folder_name = self._extract_lv_name(pool_data)
+
+        command_line = ['fquota', 'status', pool_data['id'],
+                        folder_name, '-t', 'folder']
+        rc, quota_status = self._execute(command_line)
+
+        for share_quota in quota_status:
+            if share_quota['name'] == share_name:
+                used_space = round(_bi_to_gi(float(share_quota['used'])), 2)
+
+        if new_size < used_space:
+            raise exception.ShareShrinkingPossibleDataLoss(
+                share_id=share['id'])
+
+        self._set_share_size(pool_data['id'], pool_name, share_name, new_size)
+
+        LOG.info('Successfully Shrink Share [%(share)s] '
+                 'to size [%(new_size)s G].', {
+                     'share': share['id'],
+                     'new_size': new_size})
+
+    def manage_existing(self, share, driver_options):
+        share_proto = share['share_proto'].lower()
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        pool_data = self._get_share_pool_data(pool_name)
+        volume_name = self._extract_lv_name(pool_data)
+        input_location = share['export_locations'][0]['path']
+        share_name = share['id'].replace('-', '')
+
+        ch_ip, folder_name = self._parse_location(input_location, share_proto)
+
+        if not self._check_channel_ip(ch_ip):
+            msg = _('Export location ip: [%(ch_ip)s] '
+                    'is incorrect, please use data port ip.') % {
+                        'ch_ip': ch_ip}
+            LOG.error(msg)
+            raise exception.InfortrendNASException(err=msg)
+
+        if not self._check_share_exist(pool_name, folder_name):
+            msg = _('Can not find folder [%(folder_name)s] '
+                    'in pool [%(pool_name)s].') % {
+                        'folder_name': folder_name,
+                        'pool_name': pool_name}
+            LOG.error(msg)
+            raise exception.InfortrendNASException(err=msg)
+
+        share_path = pool_data['path'] + folder_name
+        self._ensure_protocol_on(share_path, share_proto, share_name)
+        share_size = self._get_share_size(
+            pool_data['id'], pool_name, folder_name)
+
+        if not share_size:
+            msg = _('Folder [%(folder_name)s] has no size limitation, '
+                    'please set it first for Openstack management.') % {
+                        'folder_name': folder_name}
+            LOG.error(msg)
+            raise exception.InfortrendNASException(err=msg)
+
+        # rename folder name
+        command_line = ['folder', 'options', pool_data['id'], volume_name,
+                        '-k', folder_name, share_name]
+        self._execute(command_line)
+
+        location = self._export_location(
+            share_name, share_proto, pool_data['path'])
+
+        LOG.info('Successfully Manage Infortrend Share [%(folder_name)s], '
+                 'Size: [%(size)s G], Protocol: [%(share_proto)s], '
+                 'new name: [%(share_name)s].', {
+                     'folder_name': folder_name,
+                     'size': share_size,
+                     'share_proto': share_proto,
+                     'share_name': share_name})
+
+        return {'size': share_size, 'export_locations': location}
+
+    def _parse_location(self, input_location, share_proto):
+        ip = None
+        folder_name = None
+        pattern_ip = '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
+        if share_proto == 'nfs':
+            pattern_folder = '[^\/]+$'
+            ip = "".join(re.findall(pattern_ip, input_location))
+            folder_name = "".join(re.findall(pattern_folder, input_location))
+
+        elif share_proto == 'cifs':
+            pattern_folder = '[^\\\]+$'
+            ip = "".join(re.findall(pattern_ip, input_location))
+            folder_name = "".join(re.findall(pattern_folder, input_location))
+
+        if not (ip and folder_name):
+            msg = _('Export location error, please check '
+                    'ip: [%(ip)s], folder_name: [%(folder_name)s].') % {
+                        'ip': ip,
+                        'folder_name': folder_name}
+            LOG.error(msg)
+            raise exception.InfortrendNASException(err=msg)
+
+        return ip, folder_name
+
+    def _check_channel_ip(self, channel_ip):
+        return any(ip == channel_ip for ip in self.channel_dict.values())
+
+    def unmanage(self, share):
+        pool_name = share_utils.extract_host(share['host'], level='pool')
+        share_name = share['id'].replace('-', '')
+
+        if not self._check_share_exist(pool_name, share_name):
+            LOG.warning('Share [%(share_name)s] does not exist.', {
+                'share_name': share_name})
+            return
+
+        LOG.info('Successfully Unmanaged Share [%(share)s].', {
+            'share': share['id']})
diff --git a/manila/tests/conf_fixture.py b/manila/tests/conf_fixture.py
index 2518f133e9..28a1325f25 100644
--- a/manila/tests/conf_fixture.py
+++ b/manila/tests/conf_fixture.py
@@ -65,6 +65,10 @@ def set_defaults(conf):
     _safe_set_of_opts(conf, 'instorage_nas_password', 'password')
     _safe_set_of_opts(conf, 'instorage_nas_pools', 'pool0')
 
+    _safe_set_of_opts(conf, 'infortrend_nas_ip', '172.27.1.1')
+    _safe_set_of_opts(conf, 'infortrend_share_pools', 'share-pool-01')
+    _safe_set_of_opts(conf, 'infortrend_share_channels', '0,1')
+
     _safe_set_of_opts(conf, 'qnap_management_url', 'http://1.2.3.4:8080')
     _safe_set_of_opts(conf, 'qnap_share_ip', '1.2.3.4')
     _safe_set_of_opts(conf, 'qnap_nas_login', 'admin')
diff --git a/manila/tests/share/drivers/infortrend/__init__.py b/manila/tests/share/drivers/infortrend/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/manila/tests/share/drivers/infortrend/fake_infortrend_manila_data.py b/manila/tests/share/drivers/infortrend/fake_infortrend_manila_data.py
new file mode 100644
index 0000000000..c807b5f4d7
--- /dev/null
+++ b/manila/tests/share/drivers/infortrend/fake_infortrend_manila_data.py
@@ -0,0 +1,408 @@
+# Copyright (c) 2019 Infortrend Technology, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+
+class InfortrendManilaTestData(object):
+
+    fake_share_id = ['4d6984fd-8572-4467-964f-24936a8c4ea2',  # NFS
+                     'a7b933e6-bb77-4823-a86f-f2c3ab41a8a5']  # CIFS
+
+    fake_id = ['iftt8862-2226-0126-7610-chengweichou',
+               '987c8763-3333-4444-5555-666666666666']
+
+    fake_share_nfs = {
+        'share_id': fake_share_id[0],
+        'availability_zone': 'nova',
+        'terminated_at': 'datetime.datetime(2017, 5, 8, 8, 27, 25)',
+        'availability_zone_id': 'fd32d76d-b5a8-4c5c-93d7-8f09fc2a8ad3',
+        'updated_at': 'datetime.datetime(2017, 5, 8, 8, 27, 25)',
+        'share_network_id': None,
+        'export_locations': [],
+        'share_server_id': None,
+        'snapshot_id': None,
+        'deleted_at': None,
+        'id': '5a0aa06e-1c57-4996-be46-b81e360e8866',
+        'size': 30,
+        'replica_state': None,
+        'user_id': '4944594433f0405588928a4212964658',
+        'export_location': '172.27.112.223:/share-pool-01/LV-1/' +
+        fake_share_id[0],
+        'display_description': None,
+        'consistency_group_id': None,
+        'project_id': '0e63326c50a246ac81fa1a0c8e003d5b',
+        'launched_at': 'datetime.datetime(2017, 5, 8, 8, 23, 33)',
+        'scheduled_at': 'datetime.datetime(2017, 5, 8, 8, 23, 29)',
+        'status': 'deleting',
+        'share_type_id': '23d8c637-0192-47fa-b921-958f22ed772f',
+        'deleted': 'False',
+        'host': 'compute@ift-manila#share-pool-01',
+        'access_rules_status': 'active',
+        'display_name': 'nfs-01',
+        'name': 'share-5a0aa06e-1c57-4996-be46-b81e360e8866',
+        'created_at': 'datetime.datetime(2017, 5, 8, 8, 23, 29)',
+        'share_proto': 'NFS',
+        'is_public': False,
+        'source_cgsnapshot_member_id': None
+    }
+
+    fake_share_cifs = {
+        'share_id': fake_share_id[1],
+        'availability_zone': 'nova',
+        'terminated_at': None,
+        'availability_zone_id': 'fd32d76d-b5a8-4c5c-93d7-8f09fc2a8ad3',
+        'updated_at': 'datetime.datetime(2017, 5, 9, 2, 28, 35)',
+        'share_network_id': None,
+        'export_locations': [],
+        'share_server_id': None,
+        'snapshot_id': None,
+        'deleted_at': None,
+        'id': 'aac4fe64-7a9c-472a-b156-9adbb50b4d29',
+        'size': 50,
+        'replica_state': None,
+        'user_id': '4944594433f0405588928a4212964658',
+        'export_location': None,
+        'display_description': None,
+        'consistency_group_id': None,
+        'project_id': '0e63326c50a246ac81fa1a0c8e003d5b',
+        'launched_at': None,
+        'scheduled_at': 'datetime.datetime(2017, 5, 9, 2, 28, 35)',
+        'status': 'creating',
+        'share_type_id': '23d8c637-0192-47fa-b921-958f22ed772f',
+        'deleted': 'False',
+        'host': 'compute@ift-manila#share-pool-01',
+        'access_rules_status': 'active',
+        'display_name': 'cifs-01',
+        'name': 'share-aac4fe64-7a9c-472a-b156-9adbb50b4d29',
+        'created_at': 'datetime.datetime(2017, 5, 9, 2, 28, 35)',
+        'share_proto': 'CIFS',
+        'is_public': False,
+        'source_cgsnapshot_member_id': None
+    }
+
+    fake_share_cifs_no_host = {
+        'share_id': fake_share_id[1],
+        'availability_zone': 'nova',
+        'terminated_at': None,
+        'availability_zone_id': 'fd32d76d-b5a8-4c5c-93d7-8f09fc2a8ad3',
+        'updated_at': 'datetime.datetime(2017, 5, 9, 2, 28, 35)',
+        'share_network_id': None,
+        'export_locations': [],
+        'share_server_id': None,
+        'snapshot_id': None,
+        'deleted_at': None,
+        'id': 'aac4fe64-7a9c-472a-b156-9adbb50b4d29',
+        'size': 50,
+        'replica_state': None,
+        'user_id': '4944594433f0405588928a4212964658',
+        'export_location': None,
+        'display_description': None,
+        'consistency_group_id': None,
+        'project_id': '0e63326c50a246ac81fa1a0c8e003d5b',
+        'launched_at': None,
+        'scheduled_at': 'datetime.datetime(2017, 5, 9, 2, 28, 35)',
+        'status': 'creating',
+        'share_type_id': '23d8c637-0192-47fa-b921-958f22ed772f',
+        'deleted': 'False',
+        'host': '',
+        'access_rules_status': 'active',
+        'display_name': 'cifs-01',
+        'name': 'share-aac4fe64-7a9c-472a-b156-9adbb50b4d29',
+        'created_at': 'datetime.datetime(2017, 5, 9, 2, 28, 35)',
+        'share_proto': 'CIFS',
+        'is_public': False,
+        'source_cgsnapshot_member_id': None
+    }
+
+    fake_non_exist_share = {
+        'share_id': fake_id[0],
+        'availability_zone': 'nova',
+        'terminated_at': 'datetime.datetime(2017, 5, 8, 8, 27, 25)',
+        'availability_zone_id': 'fd32d76d-b5a8-4c5c-93d7-8f09fc2a8ad3',
+        'updated_at': 'datetime.datetime(2017, 5, 8, 8, 27, 25)',
+        'share_network_id': None,
+        'export_locations': [],
+        'share_server_id': None,
+        'snapshot_id': None,
+        'deleted_at': None,
+        'id': fake_id[1],
+        'size': 30,
+        'replica_state': None,
+        'user_id': '4944594433f0405588928a4212964658',
+        'export_location': '172.27.112.223:/share-pool-01/LV-1/' +
+                           fake_id[0],
+        'display_description': None,
+        'consistency_group_id': None,
+        'project_id': '0e63326c50a246ac81fa1a0c8e003d5b',
+        'launched_at': 'datetime.datetime(2017, 5, 8, 8, 23, 33)',
+        'scheduled_at': 'datetime.datetime(2017, 5, 8, 8, 23, 29)',
+        'status': 'available',
+        'share_type_id': '23d8c637-0192-47fa-b921-958f22ed772f',
+        'deleted': 'False',
+        'host': 'compute@ift-manila#share-pool-01',
+        'access_rules_status': 'active',
+        'display_name': 'nfs-01',
+        'name': 'share-5a0aa06e-1c57-4996-be46-b81e360e8866',
+        'created_at': 'datetime.datetime(2017, 5, 8, 8, 23, 29)',
+        'share_proto': 'NFS',
+        'is_public': False,
+        'source_cgsnapshot_member_id': None
+    }
+
+    fake_access_rules_nfs = [{
+        'share_id': fake_share_id[0],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 8, 41, 21)',
+        'updated_at': None,
+        'access_type': 'ip',
+        'access_to': '172.27.1.1',
+        'access_level': 'rw',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': 'fa60b50f-1428-44a2-9931-7e31f0c5b033'}, {
+        'share_id': fake_share_id[0],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 8, 45, 37)',
+        'updated_at': None,
+        'access_type': 'ip',
+        'access_to': '172.27.1.2',
+        'access_level': 'rw',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': '9bcdd5e6-11c7-4f8f-939c-84fa2f3334bc'
+    }]
+
+    fake_rule_ip_1 = [{
+        'share_id': fake_share_id[0],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 8, 41, 21)',
+        'updated_at': None,
+        'access_type': 'ip',
+        'access_to': '172.27.1.1',
+        'access_level': 'rw',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': 'fa60b50f-1428-44a2-9931-7e31f0c5b033'
+    }]
+
+    fake_rule_ip_2 = [{
+        'share_id': fake_share_id[0],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 8, 45, 37)',
+        'updated_at': None,
+        'access_type': 'ip',
+        'access_to': '172.27.1.2',
+        'access_level': 'rw',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': '9bcdd5e6-11c7-4f8f-939c-84fa2f3334bc'
+    }]
+
+    fake_access_rules_cifs = [{
+        'share_id': fake_share_id[1],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 9, 39, 18)',
+        'updated_at': None,
+        'access_type': 'user',
+        'access_to': 'user02',
+        'access_level': 'ro',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': '6e8bc969-51c9-4bbb-8e8b-020dc5fec81e'}, {
+        'share_id': fake_share_id[1],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 9, 38, 59)',
+        'updated_at': None,
+        'access_type': 'user',
+        'access_to': 'user01',
+        'access_level': 'rw',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': '0cd9926d-fac4-4122-a523-538e98752e78'
+    }]
+
+    fake_rule_user01 = [{
+        'share_id': fake_share_id[1],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 9, 38, 59)',
+        'updated_at': None,
+        'access_type': 'user',
+        'access_to': 'user01',
+        'access_level': 'rw',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': '0cd9926d-fac4-4122-a523-538e98752e78'
+    }]
+
+    fake_rule_user02 = [{
+        'share_id': fake_share_id[1],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 9, 39, 18)',
+        'updated_at': None,
+        'access_type': 'user',
+        'access_to': 'user02',
+        'access_level': 'ro',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': '6e8bc969-51c9-4bbb-8e8b-020dc5fec81e'
+    }]
+
+    fake_rule_user03 = [{
+        'share_id': fake_id[0],
+        'deleted': 'False',
+        'created_at': 'datetime.datetime(2017, 5, 9, 9, 39, 18)',
+        'updated_at': None,
+        'access_type': 'user',
+        'access_to': 'user03',
+        'access_level': 'rw',
+        'instance_mappings': [],
+        'deleted_at': None,
+        'id': fake_id[1]
+    }]
+
+    fake_share_for_manage_nfs = {
+        'share_id': '419ab73c-c0fc-4e73-b56a-70756e0b6d27',
+        'availability_zone': None,
+        'terminated_at': None,
+        'availability_zone_id': None,
+        'updated_at': None,
+        'share_network_id': None,
+        'export_locations': [{
+            'uuid': '0ebd59e4-e65e-4fda-9457-320375efd0be',
+            'deleted': 0,
+            'created_at': 'datetime.datetime(2017, 5, 10, 10, 0, 3)',
+            'updated_at': 'datetime.datetime(2017, 5, 10, 10, 0, 3)',
+            'is_admin_only': False,
+            'share_instance_id': 'd3cfe195-85cf-41e6-be4f-a96f7e7db192',
+            'path': '172.27.112.223:/share-pool-01/LV-1/test-folder',
+            'el_metadata': {},
+            'deleted_at': None,
+            'id': 83
+        }],
+        'share_server_id': None,
+        'snapshot_id': None,
+        'deleted_at': None,
+        'id': '615ac1ed-e808-40b5-8d7b-87018c6f66eb',
+        'size': None,
+        'replica_state': None,
+        'user_id': '4944594433f0405588928a4212964658',
+        'export_location': '172.27.112.223:/share-pool-01/LV-1/test-folder',
+        'display_description': '',
+        'consistency_group_id': None,
+        'project_id': '0e63326c50a246ac81fa1a0c8e003d5b',
+        'launched_at': None,
+        'scheduled_at': 'datetime.datetime(2017, 5, 10, 9, 22, 5)',
+        'status': 'manage_starting',
+        'share_type_id': '23d8c637-0192-47fa-b921-958f22ed772f',
+        'deleted': 'False',
+        'host': 'compute@ift-manila#share-pool-01',
+        'access_rules_status': 'active',
+        'display_name': 'test-manage',
+        'name': 'share-615ac1ed-e808-40b5-8d7b-87018c6f66eb',
+        'created_at': 'datetime.datetime(2017, 5, 10, 9, 22, 5)',
+        'share_proto': 'NFS',
+        'is_public': False,
+        'source_cgsnapshot_member_id': None
+    }
+
+    def _get_fake_share_for_manage(self, location=''):
+        return {
+            'share_id': '419ab73c-c0fc-4e73-b56a-70756e0b6d27',
+            'availability_zone': None,
+            'terminated_at': None,
+            'availability_zone_id': None,
+            'updated_at': None,
+            'share_network_id': None,
+            'export_locations': [{
+                'uuid': '0ebd59e4-e65e-4fda-9457-320375efd0be',
+                'deleted': 0,
+                'created_at': 'datetime.datetime(2017, 5, 10, 10, 0, 3)',
+                'updated_at': 'datetime.datetime(2017, 5, 10, 10, 0, 3)',
+                'is_admin_only': False,
+                'share_instance_id': 'd3cfe195-85cf-41e6-be4f-a96f7e7db192',
+                'path': location,
+                'el_metadata': {},
+                'deleted_at': None,
+                'id': 83
+            }],
+            'share_server_id': None,
+            'snapshot_id': None,
+            'deleted_at': None,
+            'id': '615ac1ed-e808-40b5-8d7b-87018c6f66eb',
+            'size': None,
+            'replica_state': None,
+            'user_id': '4944594433f0405588928a4212964658',
+            'export_location': location,
+            'display_description': '',
+            'consistency_group_id': None,
+            'project_id': '0e63326c50a246ac81fa1a0c8e003d5b',
+            'launched_at': None,
+            'scheduled_at': 'datetime.datetime(2017, 5, 10, 9, 22, 5)',
+            'status': 'manage_starting',
+            'share_type_id': '23d8c637-0192-47fa-b921-958f22ed772f',
+            'deleted': 'False',
+            'host': 'compute@ift-manila#share-pool-01',
+            'access_rules_status': 'active',
+            'display_name': 'test-manage',
+            'name': 'share-615ac1ed-e808-40b5-8d7b-87018c6f66eb',
+            'created_at': 'datetime.datetime(2017, 5, 10, 9, 22, 5)',
+            'share_proto': 'NFS',
+            'is_public': False,
+            'source_cgsnapshot_member_id': None
+        }
+
+    fake_share_for_manage_cifs = {
+        'share_id': '3a1222d3-c981-490a-9390-4d560ced68eb',
+        'availability_zone': None,
+        'terminated_at': None,
+        'availability_zone_id': None,
+        'updated_at': None,
+        'share_network_id': None,
+        'export_locations': [{
+            'uuid': '0ebd59e4-e65e-4fda-9457-320375efd0de',
+            'deleted': 0,
+            'created_at': 'datetime.datetime(2017, 5, 11, 10, 10, 3)',
+            'updated_at': 'datetime.datetime(2017, 5, 11, 10, 10, 3)',
+            'is_admin_only': False,
+            'share_instance_id': 'd3cfe195-85cf-41e6-be4f-a96f7e7db192',
+            'path': '\\\\172.27.113.209\\test-folder-02',
+            'el_metadata': {},
+            'deleted_at': None,
+            'id': 87
+        }],
+        'share_server_id': None,
+        'snapshot_id': None,
+        'deleted_at': None,
+        'id': 'd156baf7-5422-4c9b-8c78-ee7943d000ec',
+        'size': None,
+        'replica_state': None,
+        'user_id': '4944594433f0405588928a4212964658',
+        'export_location': '\\\\172.27.113.209\\test-folder-02',
+        'display_description': '',
+        'consistency_group_id': None,
+        'project_id': '0e63326c50a246ac81fa1a0c8e003d5b',
+        'launched_at': None,
+        'scheduled_at': 'datetime.datetime(2017, 5, 11, 3, 7, 59)',
+        'status': 'manage_starting',
+        'share_type_id': '23d8c637-0192-47fa-b921-958f22ed772f',
+        'deleted': 'False',
+        'host': 'compute@ift-manila#share-pool-01',
+        'access_rules_status': 'active',
+        'display_name': 'test-manage-02',
+        'name': 'share-d156baf7-5422-4c9b-8c78-ee7943d000ec',
+        'created_at': 'datetime.datetime(2017, 5, 11, 3, 7, 59)',
+        'share_proto': 'CIFS',
+        'is_public': False,
+        'source_cgsnapshot_member_id': None
+    }
diff --git a/manila/tests/share/drivers/infortrend/fake_infortrend_nas_data.py b/manila/tests/share/drivers/infortrend/fake_infortrend_nas_data.py
new file mode 100644
index 0000000000..b556f2a263
--- /dev/null
+++ b/manila/tests/share/drivers/infortrend/fake_infortrend_nas_data.py
@@ -0,0 +1,416 @@
+# Copyright (c) 2019 Infortrend Technology, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+
+class InfortrendNASTestData(object):
+
+    fake_share_id = ['5a0aa06e-1c57-4996-be46-b81e360e8866',  # NFS
+                     'aac4fe64-7a9c-472a-b156-9adbb50b4d29']  # CIFS
+
+    fake_share_name = [fake_share_id[0].replace('-', ''),
+                       fake_share_id[1].replace('-', '')]
+
+    fake_channel_ip = ['172.27.112.223', '172.27.113.209']
+
+    fake_service_status_data = ('(64175, 1234, 272, 0)\n\n'
+                                '{"cliCode": '
+                                '[{"Return": "0x0000", "CLI": "Successful"}], '
+                                '"returnCode": [], '
+                                '"data": '
+                                '[{"A": '
+                                '{"NFS": '
+                                '{"displayName": "NFS", '
+                                '"state_time": "2017-05-04 14:19:53", '
+                                '"enabled": true, '
+                                '"cpu_rate": "0.0", '
+                                '"mem_rate": "0.0", '
+                                '"state": "exited", '
+                                '"type": "share"}}}]}\n\n')
+
+    fake_folder_status_data = ('(64175, 1234, 1017, 0)\n\n'
+                               '{"cliCode": '
+                               '[{"Return": "0x0000", "CLI": "Successful"}], '
+                               '"returnCode": [], '
+                               '"data": '
+                               '[{"utility": "1.00", '
+                               '"used": "33886208", '
+                               '"subshare": true, '
+                               '"share": false, '
+                               '"worm": "", '
+                               '"free": "321931374592", '
+                               '"fsType": "xfs", '
+                               '"owner": "A", '
+                               '"readOnly": false, '
+                               '"modifyTime": "2017-04-27 16:16", '
+                               '"directory": "/share-pool-01/LV-1", '
+                               '"volumeId": "6541BAFB2E6C57B6", '
+                               '"mounted": true, '
+                               '"size": "321965260800"}, '
+                               '{"utility": "1.00", '
+                               '"used": "33779712", '
+                               '"subshare": false, '
+                               '"share": false, '
+                               '"worm": "", '
+                               '"free": "107287973888", '
+                               '"fsType": "xfs", '
+                               '"owner": "A", '
+                               '"readOnly": false, '
+                               '"modifyTime": "2017-04-27 15:45", '
+                               '"directory": "/share-pool-02/LV-1", '
+                               '"volumeId": "147A8FB67DA39914", '
+                               '"mounted": true, '
+                               '"size": "107321753600"}]}\n\n')
+
+    fake_nfs_status_off = [{
+        'A': {
+            'NFS': {
+                'displayName': 'NFS',
+                'state_time': '2017-05-04 14:19:53',
+                'enabled': False,
+                'cpu_rate': '0.0',
+                'mem_rate': '0.0',
+                'state': 'exited',
+                'type': 'share',
+            }
+        }
+    }]
+
+    fake_folder_status = [{
+        'utility': '1.00',
+        'used': '33886208',
+        'subshare': True,
+        'share': False,
+        'worm': '',
+        'free': '321931374592',
+        'fsType': 'xfs',
+        'owner': 'A',
+        'readOnly': False,
+        'modifyTime': '2017-04-27 16:16',
+        'directory': '/share-pool-01/LV-1',
+        'volumeId': '6541BAFB2E6C57B6',
+        'mounted': True,
+        'size': '321965260800'}, {
+        'utility': '1.00',
+        'used': '33779712',
+        'subshare': False,
+        'share': False,
+        'worm': '',
+        'free': '107287973888',
+        'fsType': 'xfs',
+        'owner': 'A',
+        'readOnly': False,
+        'modifyTime': '2017-04-27 15:45',
+        'directory': '/share-pool-02/LV-1',
+        'volumeId': '147A8FB67DA39914',
+        'mounted': True,
+        'size': '107321753600',
+    }]
+
+    def fake_get_channel_status(self, ch1_status='UP'):
+        return [{
+            'datalink': 'mgmt0',
+            'status': 'UP',
+            'typeConfig': 'DHCP',
+            'IP': '172.27.112.125',
+            'MAC': '00:d0:23:00:15:a6',
+            'netmask': '255.255.240.0',
+            'type': 'dhcp',
+            'gateway': '172.27.127.254'}, {
+            'datalink': 'CH0',
+            'status': 'UP',
+            'typeConfig': 'DHCP',
+            'IP': self.fake_channel_ip[0],
+            'MAC': '00:d0:23:80:15:a6',
+            'netmask': '255.255.240.0',
+            'type': 'dhcp',
+            'gateway': '172.27.127.254'}, {
+            'datalink': 'CH1',
+            'status': ch1_status,
+            'typeConfig': 'DHCP',
+            'IP': self.fake_channel_ip[1],
+            'MAC': '00:d0:23:40:15:a6',
+            'netmask': '255.255.240.0',
+            'type': 'dhcp',
+            'gateway': '172.27.127.254'}, {
+            'datalink': 'CH2',
+            'status': 'DOWN',
+            'typeConfig': 'DHCP',
+            'IP': '',
+            'MAC': '00:d0:23:c0:15:a6',
+            'netmask': '',
+            'type': '',
+            'gateway': ''}, {
+            'datalink': 'CH3',
+            'status': 'DOWN',
+            'typeConfig': 'DHCP',
+            'IP': '',
+            'MAC': '00:d0:23:20:15:a6',
+            'netmask': '',
+            'type': '',
+            'gateway': '',
+        }]
+
+    fake_fquota_status = [{
+        'quota': '21474836480',
+        'used': '0',
+        'name': 'test-folder',
+        'type': 'subfolder',
+        'id': '537178178'}, {
+        'quota': '32212254720',
+        'used': '0',
+        'name': fake_share_name[0],
+        'type': 'subfolder',
+        'id': '805306752'}, {
+        'quota': '53687091200',
+        'used': '21474836480',
+        'name': fake_share_name[1],
+        'type': 'subfolder',
+        'id': '69'}, {
+        'quota': '94091997184',
+        'used': '0',
+        'type': 'subfolder',
+        'id': '70',
+        "name": 'test-folder-02'
+    }]
+
+    fake_fquota_status_with_no_settings = []
+
+    def fake_get_share_status_nfs(self, status=False):
+        fake_share_status_nfs = [{
+            'ftp': False,
+            'cifs': False,
+            'oss': False,
+            'sftp': False,
+            'nfs': status,
+            'directory': '/LV-1/share-pool-01/' + self.fake_share_name[0],
+            'exist': True,
+            'afp': False,
+            'webdav': False
+        }]
+        if status:
+            fake_share_status_nfs[0]['nfs_detail'] = {
+                'hostList': [{
+                    'uid': '65534',
+                    'insecure': 'insecure',
+                    'squash': 'all',
+                    'access': 'ro',
+                    'host': '*',
+                    'gid': '65534',
+                    'mode': 'async',
+                    'no_subtree_check': 'no_subtree_check',
+                }]
+            }
+        return fake_share_status_nfs
+
+    def fake_get_share_status_cifs(self, status=False):
+        fake_share_status_cifs = [{
+            'ftp': False,
+            'cifs': status,
+            'oss': False,
+            'sftp': False,
+            'nfs': False,
+            'directory': '/share-pool-01/LV-1/' + self.fake_share_name[1],
+            'exist': True,
+            'afp': False,
+            'webdav': False
+        }]
+        if status:
+            fake_share_status_cifs[0]['cifs_detail'] = {
+                'available': True,
+                'encrypt': False,
+                'description': '',
+                'sharename': 'cifs-01',
+                'failover': '',
+                'AIO': True,
+                'priv': 'None',
+                'recycle_bin': False,
+                'ABE': True,
+            }
+        return fake_share_status_cifs
+
+    fake_subfolder_data = [{
+        'size': '6',
+        'index': '34',
+        'description': '',
+        'encryption': '',
+        'isEnd': False,
+        'share': False,
+        'volumeId': '6541BAFB2E6C57B6',
+        'quota': '',
+        'modifyTime': '2017-04-06 11:35',
+        'owner': 'A',
+        'path': '/share-pool-01/LV-1/UserHome',
+        'subshare': True,
+        'type': 'subfolder',
+        'empty': False,
+        'name': 'UserHome'}, {
+        'size': '6',
+        'index': '39',
+        'description': '',
+        'encryption': '',
+        'isEnd': False,
+        'share': False,
+        'volumeId': '6541BAFB2E6C57B6',
+        'quota': '21474836480',
+        'modifyTime': '2017-04-27 15:44',
+        'owner': 'A',
+        'path': '/share-pool-01/LV-1/test-folder',
+        'subshare': False,
+        'type': 'subfolder',
+        'empty': True,
+        'name': 'test-folder'}, {
+        'size': '6',
+        'index': '45',
+        'description': '',
+        'encryption': '',
+        'isEnd': False,
+        'share': True,
+        'volumeId': '6541BAFB2E6C57B6',
+        'quota': '32212254720',
+        'modifyTime': '2017-04-27 16:15',
+        'owner': 'A',
+        'path': '/share-pool-01/LV-1/' + fake_share_name[0],
+        'subshare': False,
+        'type': 'subfolder',
+        'empty': True,
+        'name': fake_share_name[0]}, {
+        'size': '6',
+        'index': '512',
+        'description': '',
+        'encryption': '',
+        'isEnd': True,
+        'share': True,
+        'volumeId': '6541BAFB2E6C57B6',
+        'quota': '53687091200',
+        'modifyTime': '2017-04-27 16:16',
+        'owner': 'A',
+        'path': '/share-pool-01/LV-1/' + fake_share_name[1],
+        'subshare': False,
+        'type': 'subfolder',
+        'empty': True,
+        'name': fake_share_name[1]}, {
+        'size': '6',
+        'index': '777',
+        'description': '',
+        'encryption': '',
+        'isEnd': False,
+        'share': False,
+        'volumeId': '6541BAFB2E6C57B6',
+        'quota': '94091997184',
+        'modifyTime': '2017-04-28 15:44',
+        'owner': 'A',
+        'path': '/share-pool-01/LV-1/test-folder-02',
+        'subshare': False,
+        'type': 'subfolder',
+        'empty': True,
+        'name': 'test-folder-02'
+    }]
+
+    fake_cifs_user_list = [{
+        'Superuser': 'No',
+        'Group': 'users',
+        'Description': '',
+        'Quota': 'none',
+        'PWD Expiry Date': '2291-01-19',
+        'Home Directory': '/share-pool-01/LV-1/UserHome/user01',
+        'UID': '100001',
+        'Type': 'Local',
+        'Name': 'user01'}, {
+        'Superuser': 'No',
+        'Group': 'users',
+        'Description': '',
+        'Quota': 'none',
+        'PWD Expiry Date': '2017-08-07',
+        'Home Directory': '/share-pool-01/LV-1/UserHome/user02',
+        'UID': '100002',
+        'Type': 'Local',
+        'Name': 'user02'
+    }]
+
+    fake_share_status_nfs_with_rules = [{
+        'ftp': False,
+        'cifs': False,
+        'oss': False,
+        'sftp': False,
+        'nfs': True,
+        'directory': '/share-pool-01/LV-1/' + fake_share_name[0],
+        'exist': True,
+        'nfs_detail': {
+            'hostList': [{
+                'uid': '65534',
+                'insecure': 'insecure',
+                'squash': 'all',
+                'access': 'ro',
+                'host': '*',
+                'gid': '65534',
+                'mode': 'async',
+                'no_subtree_check':
+                'no_subtree_check'}, {
+                'uid': '65534',
+                'insecure': 'insecure',
+                'squash': 'all',
+                'access': 'rw',
+                'host': '172.27.1.1',
+                'gid': '65534',
+                'mode': 'async',
+                'no_subtree_check': 'no_subtree_check'}, {
+                'uid': '65534',
+                'insecure': 'insecure',
+                'squash': 'all',
+                'access': 'rw',
+                'host': '172.27.1.2',
+                'gid': '65534',
+                'mode': 'async',
+                'no_subtree_check': 'no_subtree_check'}]
+        },
+        'afp': False,
+        'webdav': False,
+    }]
+
+    fake_share_status_cifs_with_rules = [
+        {
+            'permission': {
+                'Read': True,
+                'Write': True,
+                'Execute': True},
+            'type': 'user',
+            'id': '100001',
+            'name': 'user01'
+        }, {
+            'permission': {
+                'Read': True,
+                'Write': False,
+                'Execute': True},
+            'type': 'user',
+            'id': '100002',
+            'name': 'user02'
+        }, {
+            'permission': {
+                'Read': True,
+                'Write': False,
+                'Execute': True},
+            'type': 'group@',
+            'id': '100',
+            'name': 'users'
+        }, {
+            'permission': {
+                'Read': True,
+                'Write': False,
+                'Execute': True},
+            'type': 'other@',
+            'id': '',
+            'name': ''
+        }
+    ]
diff --git a/manila/tests/share/drivers/infortrend/test_infortrend_nas.py b/manila/tests/share/drivers/infortrend/test_infortrend_nas.py
new file mode 100644
index 0000000000..e55cc54d2d
--- /dev/null
+++ b/manila/tests/share/drivers/infortrend/test_infortrend_nas.py
@@ -0,0 +1,573 @@
+# Copyright (c) 2019 Infortrend Technology, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import ddt
+import mock
+
+from oslo_config import cfg
+
+from manila import context
+from manila import exception
+from manila.share import configuration
+from manila.share.drivers.infortrend import driver
+from manila.share.drivers.infortrend import infortrend_nas
+from manila import test
+from manila.tests.share.drivers.infortrend import fake_infortrend_manila_data
+from manila.tests.share.drivers.infortrend import fake_infortrend_nas_data
+
+CONF = cfg.CONF
+
+SUCCEED = (0, [])
+
+
+@ddt.ddt
+class InfortrendNASDriverTestCase(test.TestCase):
+    def __init__(self, *args, **kwargs):
+        super(InfortrendNASDriverTestCase, self).__init__(*args, **kwargs)
+        self._ctxt = context.get_admin_context()
+        self.nas_data = fake_infortrend_nas_data.InfortrendNASTestData()
+        self.m_data = fake_infortrend_manila_data.InfortrendManilaTestData()
+
+    def setUp(self):
+        CONF.set_default('driver_handles_share_servers', False)
+        CONF.set_default('infortrend_nas_ip', '172.27.1.1')
+        CONF.set_default('infortrend_nas_user', 'fake_user')
+        CONF.set_default('infortrend_nas_password', 'fake_password')
+        CONF.set_default('infortrend_nas_ssh_key', 'fake_sshkey')
+        CONF.set_default('infortrend_share_pools', 'share-pool-01')
+        CONF.set_default('infortrend_share_channels', '0,1')
+        self.fake_conf = configuration.Configuration(None)
+        super(InfortrendNASDriverTestCase, self).setUp()
+
+    def _get_driver(self, fake_conf, init_dict=False):
+        self._driver = driver.InfortrendNASDriver(
+            configuration=fake_conf)
+        self._iftnas = self._driver.ift_nas
+        self.pool_id = ['6541BAFB2E6C57B6']
+        self.pool_path = ['/share-pool-01/LV-1/']
+
+        if init_dict:
+            self._iftnas.pool_dict = {
+                'share-pool-01': {
+                    'id': self.pool_id[0],
+                    'path': self.pool_path[0],
+                }
+            }
+            self._iftnas.channel_dict = {
+                '0': self.nas_data.fake_channel_ip[0],
+                '1': self.nas_data.fake_channel_ip[1],
+            }
+
+    def test_no_login_ssh_key_and_pass(self):
+        self.fake_conf.set_default('infortrend_nas_password', None)
+        self.fake_conf.set_default('infortrend_nas_ssh_key', None)
+
+        self.assertRaises(
+            exception.InvalidParameterValue,
+            self._get_driver,
+            self.fake_conf)
+
+    def test_parser_with_service_status(self):
+        self._get_driver(self.fake_conf)
+        expect_service_status = [{
+            'A': {
+                'NFS': {
+                    'displayName': 'NFS',
+                    'state_time': '2017-05-04 14:19:53',
+                    'enabled': True,
+                    'cpu_rate': '0.0',
+                    'mem_rate': '0.0',
+                    'state': 'exited',
+                    'type': 'share',
+                }
+            }
+        }]
+
+        rc, service_status = self._iftnas._parser(
+            self.nas_data.fake_service_status_data)
+
+        self.assertEqual(0, rc)
+        self.assertDictListMatch(expect_service_status, service_status)
+
+    def test_parser_with_folder_status(self):
+        self._get_driver(self.fake_conf)
+        expect_folder_status = [{
+            'utility': '1.00',
+            'used': '33886208',
+            'subshare': True,
+            'share': False,
+            'worm': '',
+            'free': '321931374592',
+            'fsType': 'xfs',
+            'owner': 'A',
+            'readOnly': False,
+            'modifyTime': '2017-04-27 16:16',
+            'directory': self.pool_path[0][:-1],
+            'volumeId': self.pool_id[0],
+            'mounted': True,
+            'size': '321965260800'}, {
+            'utility': '1.00',
+            'used': '33779712',
+            'subshare': False,
+            'share': False,
+            'worm': '',
+            'free': '107287973888',
+            'fsType': 'xfs',
+            'owner': 'A',
+            'readOnly': False,
+            'modifyTime': '2017-04-27 15:45',
+            'directory': '/share-pool-02/LV-1',
+            'volumeId': '147A8FB67DA39914',
+            'mounted': True,
+            'size': '107321753600'
+        }]
+
+        rc, folder_status = self._iftnas._parser(
+            self.nas_data.fake_folder_status_data)
+
+        self.assertEqual(0, rc)
+        self.assertDictListMatch(expect_folder_status, folder_status)
+
+    def test_ensure_service_on(self):
+        self._get_driver(self.fake_conf)
+        mock_execute = mock.Mock(
+            side_effect=[(0, self.nas_data.fake_nfs_status_off), SUCCEED])
+        self._iftnas._execute = mock_execute
+
+        self._iftnas._ensure_service_on('nfs')
+
+        mock_execute.assert_called_with(['service', 'restart', 'nfs'])
+
+    def test_check_channels_status(self):
+        self._get_driver(self.fake_conf)
+        expect_channel_dict = {
+            '0': self.nas_data.fake_channel_ip[0],
+            '1': self.nas_data.fake_channel_ip[1],
+        }
+
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_get_channel_status()))
+
+        self._iftnas._check_channels_status()
+
+        self.assertDictMatch(expect_channel_dict, self._iftnas.channel_dict)
+
+    @mock.patch.object(infortrend_nas.LOG, 'warning')
+    def test_channel_status_down(self, log_warning):
+        self._get_driver(self.fake_conf)
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_get_channel_status('DOWN')))
+
+        self._iftnas._check_channels_status()
+
+        self.assertEqual(1, log_warning.call_count)
+
+    @mock.patch.object(infortrend_nas.LOG, 'error')
+    def test_invalid_channel(self, log_error):
+        self.fake_conf.set_default('infortrend_share_channels', '0, 6')
+        self._get_driver(self.fake_conf)
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_get_channel_status()))
+
+        self.assertRaises(
+            exception.InfortrendNASException,
+            self._iftnas._check_channels_status)
+
+    def test_check_pools_setup(self):
+        self._get_driver(self.fake_conf)
+        expect_pool_dict = {
+            'share-pool-01': {
+                'id': self.pool_id[0],
+                'path': self.pool_path[0],
+            }
+        }
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_folder_status))
+
+        self._iftnas._check_pools_setup()
+
+        self.assertDictMatch(expect_pool_dict, self._iftnas.pool_dict)
+
+    def test_unknow_pools_setup(self):
+        self.fake_conf.set_default(
+            'infortrend_share_pools', 'chengwei, share-pool-01')
+        self._get_driver(self.fake_conf)
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_folder_status))
+
+        self.assertRaises(
+            exception.InfortrendNASException,
+            self._iftnas._check_pools_setup)
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_get_pool_quota_used(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        mock_execute.return_value = (0, self.nas_data.fake_fquota_status)
+
+        pool_quota = self._iftnas._get_pool_quota_used('share-pool-01')
+
+        mock_execute.assert_called_with(
+            ['fquota', 'status', self.pool_id[0],
+             'LV-1', '-t', 'folder'])
+        self.assertEqual(201466179584, pool_quota)
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_create_share_nfs(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        fake_share_id = self.m_data.fake_share_nfs['id']
+        fake_share_name = fake_share_id.replace('-', '')
+        expect_locations = [
+            self.nas_data.fake_channel_ip[0] +
+            ':/share-pool-01/LV-1/' + fake_share_name,
+            self.nas_data.fake_channel_ip[1] +
+            ':/share-pool-01/LV-1/' + fake_share_name,
+        ]
+        mock_execute.side_effect = [
+            SUCCEED,  # create folder
+            SUCCEED,  # set size
+            (0, self.nas_data.fake_get_share_status_nfs()),  # check proto
+            SUCCEED,  # enable proto
+            (0, self.nas_data.fake_get_channel_status())  # update channel
+        ]
+
+        locations = self._driver.create_share(
+            self._ctxt, self.m_data.fake_share_nfs)
+
+        self.assertEqual(expect_locations, locations)
+        mock_execute.assert_any_call(
+            ['share', self.pool_path[0] + fake_share_name, 'nfs', 'on'])
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_create_share_cifs(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        fake_share_id = self.m_data.fake_share_cifs['id']
+        fake_share_name = fake_share_id.replace('-', '')
+        expect_locations = [
+            '\\\\' + self.nas_data.fake_channel_ip[0] +
+            '\\' + fake_share_name,
+            '\\\\' + self.nas_data.fake_channel_ip[1] +
+            '\\' + fake_share_name,
+        ]
+        mock_execute.side_effect = [
+            SUCCEED,  # create folder
+            SUCCEED,  # set size
+            (0, self.nas_data.fake_get_share_status_cifs()),  # check proto
+            SUCCEED,  # enable proto
+            (0, self.nas_data.fake_get_channel_status())  # update channel
+        ]
+
+        locations = self._driver.create_share(
+            self._ctxt, self.m_data.fake_share_cifs)
+
+        self.assertEqual(expect_locations, locations)
+        mock_execute.assert_any_call(
+            ['share', self.pool_path[0] + fake_share_name,
+             'cifs', 'on', '-n', fake_share_name])
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_delete_share_nfs(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        fake_share_id = self.m_data.fake_share_nfs['id']
+        fake_share_name = fake_share_id.replace('-', '')
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_subfolder_data),  # pagelist folder
+            SUCCEED,  # delete folder
+        ]
+
+        self._driver.delete_share(
+            self._ctxt, self.m_data.fake_share_nfs)
+
+        mock_execute.assert_any_call(
+            ['folder', 'options', self.pool_id[0],
+             'LV-1', '-d', fake_share_name])
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_delete_share_cifs(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        fake_share_id = self.m_data.fake_share_cifs['id']
+        fake_share_name = fake_share_id.replace('-', '')
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_subfolder_data),  # pagelist folder
+            SUCCEED,  # delete folder
+        ]
+
+        self._driver.delete_share(
+            self._ctxt, self.m_data.fake_share_cifs)
+
+        mock_execute.assert_any_call(
+            ['folder', 'options', self.pool_id[0],
+             'LV-1', '-d', fake_share_name])
+
+    @mock.patch.object(infortrend_nas.LOG, 'warning')
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_delete_non_exist_share(self, mock_execute, log_warning):
+        self._get_driver(self.fake_conf, True)
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_subfolder_data),  # pagelist folder
+        ]
+
+        self._driver.delete_share(
+            self._ctxt, self.m_data.fake_non_exist_share)
+
+        self.assertEqual(1, log_warning.call_count)
+
+    def test_get_pool(self):
+        self._get_driver(self.fake_conf, True)
+        pool = self._driver.get_pool(self.m_data.fake_share_nfs)
+
+        self.assertEqual('share-pool-01', pool)
+
+    def test_get_pool_without_host(self):
+        self._get_driver(self.fake_conf, True)
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_subfolder_data))
+
+        pool = self._driver.get_pool(self.m_data.fake_share_cifs_no_host)
+
+        self.assertEqual('share-pool-01', pool)
+
+    def test_ensure_share_nfs(self):
+        self._get_driver(self.fake_conf, True)
+        share_id = self.m_data.fake_share_nfs['id']
+        share_name = share_id.replace('-', '')
+        share_path = self.pool_path[0] + share_name
+        expect_locations = [
+            self.nas_data.fake_channel_ip[0] + ':' + share_path,
+            self.nas_data.fake_channel_ip[1] + ':' + share_path,
+        ]
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_get_channel_status()))
+
+        locations = self._driver.ensure_share(
+            self._ctxt, self.m_data.fake_share_nfs)
+
+        self.assertEqual(expect_locations, locations)
+
+    def test_ensure_share_cifs(self):
+        self._get_driver(self.fake_conf, True)
+        share_id = self.m_data.fake_share_cifs['id']
+        share_name = share_id.replace('-', '')
+        expect_locations = [
+            '\\\\' + self.nas_data.fake_channel_ip[0] +
+            '\\' + share_name,
+            '\\\\' + self.nas_data.fake_channel_ip[1] +
+            '\\' + share_name,
+        ]
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_get_channel_status()))
+
+        locations = self._driver.ensure_share(
+            self._ctxt, self.m_data.fake_share_cifs)
+
+        self.assertEqual(expect_locations, locations)
+
+    def test_extend_share(self):
+        self._get_driver(self.fake_conf, True)
+        share_id = self.m_data.fake_share_nfs['id']
+        share_name = share_id.replace('-', '')
+        self._iftnas._execute = mock.Mock(return_value=SUCCEED)
+
+        self._driver.extend_share(self.m_data.fake_share_nfs, 100)
+
+        self._iftnas._execute.assert_called_once_with(
+            ['fquota', 'create', self.pool_id[0], 'LV-1',
+             share_name, '100G', '-t', 'folder'])
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_shrink_share(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        share_id = self.m_data.fake_share_nfs['id']
+        share_name = share_id.replace('-', '')
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_fquota_status),  # check used
+            SUCCEED,
+        ]
+
+        self._driver.shrink_share(self.m_data.fake_share_nfs, 10)
+
+        mock_execute.assert_has_calls([
+            mock.call(['fquota', 'status', self.pool_id[0],
+                       'LV-1', '-t', 'folder']),
+            mock.call(['fquota', 'create', self.pool_id[0],
+                       'LV-1', share_name, '10G', '-t', 'folder'])])
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_shrink_share_smaller_than_used_size(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_fquota_status),  # check used
+        ]
+
+        self.assertRaises(
+            exception.ShareShrinkingPossibleDataLoss,
+            self._driver.shrink_share,
+            self.m_data.fake_share_cifs,
+            10)
+
+    def test_get_share_size(self):
+        self._get_driver(self.fake_conf, True)
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_fquota_status))
+
+        size = self._iftnas._get_share_size('', '', 'test-folder-02')
+
+        self.assertEqual(87.63, size)
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_manage_existing_nfs(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        share_id = self.m_data.fake_share_for_manage_nfs['id']
+        share_name = share_id.replace('-', '')
+        origin_share_path = self.pool_path[0] + 'test-folder'
+        export_share_path = self.pool_path[0] + share_name
+        expect_result = {
+            'size': 20.0,
+            'export_locations': [
+                self.nas_data.fake_channel_ip[0] + ':' + export_share_path,
+                self.nas_data.fake_channel_ip[1] + ':' + export_share_path,
+            ]
+        }
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_subfolder_data),  # pagelist folder
+            (0, self.nas_data.fake_get_share_status_nfs()),  # check proto
+            SUCCEED,  # enable nfs
+            (0, self.nas_data.fake_fquota_status),  # get share size
+            SUCCEED,  # rename share
+            (0, self.nas_data.fake_get_channel_status())  # update channel
+        ]
+
+        result = self._driver.manage_existing(
+            self.m_data.fake_share_for_manage_nfs,
+            {}
+        )
+
+        self.assertEqual(expect_result, result)
+        mock_execute.assert_has_calls([
+            mock.call(['pagelist', 'folder', self.pool_path[0]]),
+            mock.call(['share', 'status', '-f', origin_share_path]),
+            mock.call(['share', origin_share_path, 'nfs', 'on']),
+            mock.call(['fquota', 'status', self.pool_id[0],
+                       origin_share_path.split('/')[3], '-t', 'folder']),
+            mock.call(['folder', 'options', self.pool_id[0],
+                       'LV-1', '-k', 'test-folder', share_name]),
+            mock.call(['ifconfig', 'inet', 'show']),
+        ])
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_manage_existing_cifs(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        share_id = self.m_data.fake_share_for_manage_cifs['id']
+        share_name = share_id.replace('-', '')
+        origin_share_path = self.pool_path[0] + 'test-folder-02'
+        expect_result = {
+            'size': 87.63,
+            'export_locations': [
+                '\\\\' + self.nas_data.fake_channel_ip[0] + '\\' + share_name,
+                '\\\\' + self.nas_data.fake_channel_ip[1] + '\\' + share_name,
+            ]
+        }
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_subfolder_data),  # pagelist folder
+            (0, self.nas_data.fake_get_share_status_cifs()),  # check proto
+            SUCCEED,  # enable cifs
+            (0, self.nas_data.fake_fquota_status),  # get share size
+            SUCCEED,  # rename share
+            (0, self.nas_data.fake_get_channel_status())  # update channel
+        ]
+
+        result = self._driver.manage_existing(
+            self.m_data.fake_share_for_manage_cifs,
+            {}
+        )
+
+        self.assertEqual(expect_result, result)
+        mock_execute.assert_has_calls([
+            mock.call(['pagelist', 'folder', self.pool_path[0]]),
+            mock.call(['share', 'status', '-f', origin_share_path]),
+            mock.call(['share', origin_share_path, 'cifs', 'on',
+                       '-n', share_name]),
+            mock.call(['fquota', 'status', self.pool_id[0],
+                       origin_share_path.split('/')[3], '-t', 'folder']),
+            mock.call(['folder', 'options', self.pool_id[0],
+                       'LV-1', '-k', 'test-folder-02', share_name]),
+            mock.call(['ifconfig', 'inet', 'show']),
+        ])
+
+    def test_manage_existing_with_no_location(self):
+        self._get_driver(self.fake_conf, True)
+        fake_share = self.m_data._get_fake_share_for_manage('')
+
+        self.assertRaises(
+            exception.InfortrendNASException,
+            self._driver.manage_existing,
+            fake_share, {})
+
+    @ddt.data('172.27.1.1:/share-pool-01/LV-1/test-folder',
+              '172.27.112.223:/share-pool-01/LV-1/some-folder')
+    def test_manage_existing_wrong_ip_or_name(self, fake_share_path):
+        self._get_driver(self.fake_conf, True)
+        fake_share = self.m_data._get_fake_share_for_manage(fake_share_path)
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_subfolder_data))
+
+        self.assertRaises(
+            exception.InfortrendNASException,
+            self._driver.manage_existing,
+            fake_share, {})
+
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_manage_existing_with_no_size_setting(self, mock_execute):
+        self._get_driver(self.fake_conf, True)
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_subfolder_data),  # pagelist folder
+            (0, self.nas_data.fake_get_share_status_nfs()),  # check proto
+            SUCCEED,  # enable nfs
+            (0, self.nas_data.fake_fquota_status_with_no_settings),
+        ]
+
+        self.assertRaises(
+            exception.InfortrendNASException,
+            self._driver.manage_existing,
+            self.m_data.fake_share_for_manage_nfs,
+            {})
+
+    @ddt.data('NFS', 'CIFS')
+    @mock.patch.object(infortrend_nas.InfortrendNAS, '_execute')
+    def test_unmanage(self, protocol, mock_execute):
+        share_to_unmanage = (self.m_data.fake_share_nfs
+                             if protocol == 'NFS' else
+                             self.m_data.fake_share_cifs)
+        self._get_driver(self.fake_conf, True)
+        mock_execute.side_effect = [
+            (0, self.nas_data.fake_subfolder_data),  # pagelist folder
+        ]
+
+        self._driver.unmanage(share_to_unmanage)
+
+        mock_execute.assert_called_once_with(
+            ['pagelist', 'folder', self.pool_path[0]],
+        )
+
+    @mock.patch.object(infortrend_nas.LOG, 'warning')
+    def test_unmanage_share_not_exist(self, log_warning):
+        self._get_driver(self.fake_conf, True)
+        self._iftnas._execute = mock.Mock(
+            return_value=(0, self.nas_data.fake_subfolder_data))
+
+        self._driver.unmanage(
+            self.m_data.fake_share_for_manage_nfs,
+        )
+
+        self.assertEqual(1, log_warning.call_count)
diff --git a/releasenotes/notes/infortrend-manila-driver-a1a2af20de6368cb.yaml b/releasenotes/notes/infortrend-manila-driver-a1a2af20de6368cb.yaml
new file mode 100644
index 0000000000..b7f87f333c
--- /dev/null
+++ b/releasenotes/notes/infortrend-manila-driver-a1a2af20de6368cb.yaml
@@ -0,0 +1,5 @@
+---
+prelude: >
+    Added Manila share driver for Infortrend storage systems.
+features:
+  - The new Infortrend driver supports GS/GSe Family storage systems.