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 b266cc7a42..f6623192d0 100644
--- a/doc/source/admin/share_back_ends_feature_support_mapping.rst
+++ b/doc/source/admin/share_back_ends_feature_support_mapping.rst
@@ -95,6 +95,8 @@ Mapping of share drivers and share features support
 +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
 |                  QNAP                  |           O           |           O           |             O            |            \-            |            O           |                 O                 |             O            |          \-        |          \-        |
 +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
+|         Pure Storage FlashBlade        |           X           |          \-           |             X            |             X            |            X           |                \-                 |            \-            |           X        |          \-        |
++----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
 
 Mapping of share drivers and share access rules support
 -------------------------------------------------------
@@ -164,6 +166,8 @@ Mapping of share drivers and share access rules support
 +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
 |                  QNAP                  |    NFS (O)   |      \-      |      \-        |     \-     |      \-      |    NFS (O)   |      \-      |       \-       |     \-     |     \-     |
 +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
+|        Pure Storage FlashBlade         |    NFS (X)   |      \-      |      \-        |     \-     |      \-      |    NFS (X)   |      \-      |       \-       |     \-     |     \-     |
++----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
 
 Mapping of share drivers and security services support
 ------------------------------------------------------
@@ -231,6 +235,8 @@ Mapping of share drivers and security services support
 +----------------------------------------+------------------+-----------------+------------------+
 |                 QNAP                   |        \-        |        \-       |        \-        |
 +----------------------------------------+------------------+-----------------+------------------+
+|        Pure Storage FlashBlade         |        \-        |        \-       |        \-        |
++----------------------------------------+------------------+-----------------+------------------+
 
 Mapping of share drivers and common capabilities
 ------------------------------------------------
@@ -300,6 +306,8 @@ More information: :ref:`capabilities_and_extra_specs`
 +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
 |            INSPUR InStorage            |     \-    |      T     |   \-   |      \-     |       \-          |          T         | \-  |             \-             |          \-        |          \-        |       T      |      \-      |
 +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
+|         Pure Storage FlashBlade        |     \-    |      X     |  \-    |     \-      |        X          |         \-         | \-  |             \-             |           X        |          \-        |       X      |      \-      |
++----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
 
 .. note::
 
diff --git a/doc/source/configuration/shared-file-systems/drivers.rst b/doc/source/configuration/shared-file-systems/drivers.rst
index 2141c1be40..f2edb69009 100644
--- a/doc/source/configuration/shared-file-systems/drivers.rst
+++ b/doc/source/configuration/shared-file-systems/drivers.rst
@@ -34,6 +34,7 @@ Share drivers
    drivers/quobyte-driver.rst
    drivers/windows-smb-driver.rst
    drivers/nexentastor5-driver.rst
+   drivers/purestorage-flashblade-driver.rst
 
 
 To use different share drivers for the Shared File Systems service, use the
diff --git a/doc/source/configuration/shared-file-systems/drivers/purestorage-flashblade-driver.rst b/doc/source/configuration/shared-file-systems/drivers/purestorage-flashblade-driver.rst
new file mode 100644
index 0000000000..66d6e0c7bd
--- /dev/null
+++ b/doc/source/configuration/shared-file-systems/drivers/purestorage-flashblade-driver.rst
@@ -0,0 +1,123 @@
+==============================
+Pure Storage FlashBlade driver
+==============================
+
+The Pure Storage FlashBlade driver provides support for managing filesystem shares
+on the Pure Storage FlashBlade storage systems.
+
+The driver is compatible with Pure Storage FlashBlades that support REST API version
+1.6 or higher (Purity//FB v2.3.0 or higher).
+This section explains how to configure the FlashBlade driver.
+
+Supported operations
+~~~~~~~~~~~~~~~~~~~~
+
+- Create and delete NFS shares.
+
+- Extend/Shrink a share.
+
+- Create and delete filesystem snapshots (No support for create-from or mount).
+
+- Revert to Snapshot.
+
+- Both RW and RO access levels are supported.
+
+- Set access rights to NFS shares.
+
+  Note the following limitations:
+
+  - Only IP (for NFS shares) access types are supported.
+
+External package installation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The driver requires the ``purity_fb`` package for communicating with
+FlashBlade systems. Install the package from PyPI using the following command:
+
+.. code-block:: console
+
+   $ pip install purity_fb
+
+Driver configuration
+~~~~~~~~~~~~~~~~~~~~
+
+Edit the ``manila.conf`` file, which is usually located under the following
+path ``/etc/manila/manila.conf``.
+
+* Add a section for the FlashBlade driver back end.
+
+* Under the ``[DEFAULT]`` section, set the ``enabled_share_backends`` parameter
+  with the name of the new back-end section.
+
+Configure the driver back-end section with the parameters below.
+
+* Configure the driver name by setting the following parameter:
+
+  .. code-block:: ini
+
+     share_driver = manila.share.drivers.purestorage.flashblade.FlashBladeShareDriver
+
+* Configure the management and data VIPs of the FlashBlade array by adding the
+  following parameters:
+
+  .. code-block:: ini
+
+     flashblade_mgmt_vip = FlashBlade management VIP
+     flashblade_data_vip = FlashBlade data VIP
+
+* Configure user credentials:
+
+  The driver requires a FlashBlade user with administrative privileges.
+  We recommend creating a dedicated OpenStack user account
+  that holds an administrative user role.
+  Refer to the FlashBlade manuals for details on user account management.
+  Configure the user credentials by adding the following parameters:
+
+  .. code-block:: ini
+
+     flashblade_api = FlashBlade API token for admin-privileged user
+
+* (Optional) Configure File System and Snapshot Eradication:
+
+  The option, when enabled, all FlashBlade file systems and snapshots will
+  be eradicated at the time of deletion in Manila. Data will NOT be
+  recoverable after a delete with this set to True! When disabled,
+  file systems and snapshots will go into pending eradication state
+  and can be recovered. Recovery of these pending eradication snapshots
+  cannot be accomplished through Manila. These snapshots will self-eradicate
+  after 24 hours unless manually restored. The default setting is True.
+
+  .. code-block:: ini
+
+     flashblade_eradicate = { True | False }
+
+* The back-end name is an identifier for the back end.
+  We recommend using the same name as the name of the section.
+  Configure the back-end name by adding the following parameter:
+
+  .. code-block:: ini
+
+     share_backend_name = back-end name
+
+Configuration example
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: ini
+
+   [DEFAULT]
+   enabled_share_backends = flashblade-1
+
+   [flashblade-1]
+   share_driver = manila.share.drivers.purestorage.flashblade.FlashBladeShareDriver
+   share_backend_name = flashblade-1
+   driver_handles_share_servers = false
+   flashblade_mgmt_vip = 10.1.2.3
+   flashblade_data_vip = 10.1.2.4
+   flashblade_api = pureuser API
+
+Driver options
+~~~~~~~~~~~~~~
+
+Configuration options specific to this driver:
+
+.. include:: ../../tables/manila-purestorage-flashblade.inc
diff --git a/doc/source/configuration/tables/manila-purestorage-flashblade.inc b/doc/source/configuration/tables/manila-purestorage-flashblade.inc
new file mode 100644
index 0000000000..6371a48139
--- /dev/null
+++ b/doc/source/configuration/tables/manila-purestorage-flashblade.inc
@@ -0,0 +1,18 @@
+.. _manila-purestorage-flashblade:
+
+.. list-table:: Description of Pure Storage FlashBlade share driver configuration options
+   :header-rows: 1
+   :class: config-ref-table
+
+   * - Configuration option = Default value
+     - Description
+   * - **[DEFAULT]**
+     -
+   * - ``flashblade_mgmt_vip`` = ``None``
+     - (String) The name (or IP address) for the Pure Storage FlashBlade storage system management port.
+   * - ``flashblade_data_vip`` = ``None``
+     - (String) The name (or IP address) for the Pure Storage FlashBlade storage system data port.
+   * - ``flashblade_api`` = ``None``
+     - (String) API token for an administrative level user account.
+   * - ``flashblade_eradicate`` = ``True``
+     - (Boolean) Enable or disable filesystem and snapshot eradication on delete.
diff --git a/manila/opts.py b/manila/opts.py
index 0d0985fd04..c013b9d8d9 100644
--- a/manila/opts.py
+++ b/manila/opts.py
@@ -81,6 +81,7 @@ import manila.share.drivers.lvm
 import manila.share.drivers.maprfs.maprfs_native
 import manila.share.drivers.netapp.options
 import manila.share.drivers.nexenta.options
+import manila.share.drivers.purestorage.flashblade
 import manila.share.drivers.qnap.qnap
 import manila.share.drivers.quobyte.quobyte
 import manila.share.drivers.service_instance
@@ -177,6 +178,9 @@ _global_opt_lists = [
     manila.share.drivers.nexenta.options.nexenta_connection_opts,
     manila.share.drivers.nexenta.options.nexenta_dataset_opts,
     manila.share.drivers.nexenta.options.nexenta_nfs_opts,
+    manila.share.drivers.purestorage.flashblade.flashblade_auth_opts,
+    manila.share.drivers.purestorage.flashblade.flashblade_extra_opts,
+    manila.share.drivers.purestorage.flashblade.flashblade_connection_opts,
     manila.share.drivers.qnap.qnap.qnap_manila_opts,
     manila.share.drivers.quobyte.quobyte.quobyte_manila_share_opts,
     manila.share.drivers.service_instance.common_opts,
diff --git a/manila/share/drivers/purestorage/__init__.py b/manila/share/drivers/purestorage/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/manila/share/drivers/purestorage/flashblade.py b/manila/share/drivers/purestorage/flashblade.py
new file mode 100644
index 0000000000..06ff638a46
--- /dev/null
+++ b/manila/share/drivers/purestorage/flashblade.py
@@ -0,0 +1,467 @@
+# Copyright 2021 Pure Storage 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.
+"""
+Pure Storage FlashBlade Share Driver
+"""
+
+import functools
+import platform
+
+from oslo_config import cfg
+from oslo_log import log as logging
+from oslo_utils import units
+
+from manila import exception
+from manila.i18n import _
+from manila.share import driver
+
+HAS_PURITY_FB = True
+try:
+    import purity_fb
+except ImportError:
+    purity_fb = None
+
+LOG = logging.getLogger(__name__)
+
+flashblade_connection_opts = [
+    cfg.HostAddressOpt(
+        "flashblade_mgmt_vip",
+        help="The name (or IP address) for the Pure Storage "
+        "FlashBlade storage system management VIP.",
+    ),
+    cfg.HostAddressOpt(
+        "flashblade_data_vip",
+        help="The name (or IP address) for the Pure Storage "
+        "FlashBlade storage system data VIP.",
+    ),
+]
+
+flashblade_auth_opts = [
+    cfg.StrOpt(
+        "flashblade_api",
+        help=("API token for an administrative user account"),
+        secret=True,
+    ),
+]
+
+flashblade_extra_opts = [
+    cfg.BoolOpt(
+        "flashblade_eradicate",
+        default=True,
+        help="When enabled, all FlashBlade file systems and snapshots "
+        "will be eradicated at the time of deletion in Manila. "
+        "Data will NOT be recoverable after a delete with this "
+        "set to True! When disabled, file systems and snapshots "
+        "will go into pending eradication state and can be "
+        "recovered.)",
+    ),
+]
+
+CONF = cfg.CONF
+CONF.register_opts(flashblade_connection_opts)
+CONF.register_opts(flashblade_auth_opts)
+CONF.register_opts(flashblade_extra_opts)
+
+
+def purity_fb_to_manila_exceptions(func):
+    @functools.wraps(func)
+    def wrapper(*args, **kwargs):
+        try:
+            return func(*args, **kwargs)
+        except purity_fb.rest.ApiException as ex:
+            msg = _("Caught exception from purity_fb: %s") % ex
+            LOG.exception(msg)
+            raise exception.ShareBackendException(msg=msg)
+
+    return wrapper
+
+
+class FlashBladeShareDriver(driver.ShareDriver):
+
+    VERSION = "2.0"  # driver version
+    USER_AGENT_BASE = "OpenStack Manila"
+
+    def __init__(self, *args, **kwargs):
+        super(FlashBladeShareDriver, self).__init__(False, *args, **kwargs)
+        self.configuration.append_config_values(flashblade_connection_opts)
+        self.configuration.append_config_values(flashblade_auth_opts)
+        self.configuration.append_config_values(flashblade_extra_opts)
+        self._user_agent = "%(base)s %(class)s/%(version)s (%(platform)s)" % {
+            "base": self.USER_AGENT_BASE,
+            "class": self.__class__.__name__,
+            "version": self.VERSION,
+            "platform": platform.platform(),
+        }
+
+    def do_setup(self, context):
+        """Driver initialization"""
+        if purity_fb is None:
+            msg = _(
+                "Missing 'purity_fb' python module, ensure the library"
+                " is installed and available."
+            )
+            raise exception.ManilaException(message=msg)
+
+        self.api = self._safe_get_from_config_or_fail("flashblade_api")
+        self.management_address = self._safe_get_from_config_or_fail(
+            "flashblade_mgmt_vip"
+        )
+        self.data_address = self._safe_get_from_config_or_fail(
+            "flashblade_data_vip"
+        )
+        self._sys = purity_fb.PurityFb(self.management_address)
+        self._sys.disable_verify_ssl()
+        try:
+            self._sys.login(self.api)
+            self._sys._api_client.user_agent = self._user_agent
+        except purity_fb.rest.ApiException as ex:
+            msg = _("Exception when logging into the array: %s\n") % ex
+            LOG.exception(msg)
+            raise exception.ManilaException(message=msg)
+
+        backend_name = self.configuration.safe_get("share_backend_name")
+        self._backend_name = backend_name or self.__class__.__name__
+
+        LOG.debug("setup complete")
+
+    def _update_share_stats(self, data=None):
+        """Retrieve stats info from share group."""
+        (
+            free_capacity_bytes,
+            physical_capacity_bytes,
+            provisioned_cap_bytes,
+            data_reduction,
+        ) = self._get_available_capacity()
+
+        reserved_share_percentage = self.configuration.safe_get(
+            "reserved_safe_percentage"
+        )
+        if reserved_share_percentage is None:
+            reserved_share_percentage = 0
+
+        data = dict(
+            share_backend_name=self._backend_name,
+            vendor_name="PURE STORAGE",
+            driver_version=self.VERSION,
+            storage_protocol="NFS",
+            data_reduction=data_reduction,
+            reserved_percentage=reserved_share_percentage,
+            total_capacity_gb=float(physical_capacity_bytes) / units.Gi,
+            free_capacity_gb=float(free_capacity_bytes) / units.Gi,
+            provisioned_capacity_gb=float(provisioned_cap_bytes) / units.Gi,
+            snapshot_support=True,
+            create_share_from_snapshot_support=False,
+            mount_snapshot_support=False,
+            revert_to_snapshot_support=True,
+            thin_provisioning=True,
+        )
+
+        super(FlashBladeShareDriver, self)._update_share_stats(data)
+
+    def _get_available_capacity(self):
+        space = self._sys.arrays.list_arrays_space()
+        array_space = space.items[0]
+        data_reduction = array_space.space.data_reduction
+        physical_capacity_bytes = array_space.capacity
+        used_capacity_bytes = array_space.space.total_physical
+        free_capacity_bytes = physical_capacity_bytes - used_capacity_bytes
+        provisioned_capacity_bytes = array_space.space.unique
+        return (
+            free_capacity_bytes,
+            physical_capacity_bytes,
+            provisioned_capacity_bytes,
+            data_reduction,
+        )
+
+    def _safe_get_from_config_or_fail(self, config_parameter):
+        config_value = self.configuration.safe_get(config_parameter)
+        if not config_value:
+            reason = _(
+                "%(config_parameter)s configuration parameter "
+                "must be specified"
+            ) % {"config_parameter": config_parameter}
+            LOG.exception(reason)
+            raise exception.BadConfigurationException(reason=reason)
+        return config_value
+
+    def _make_source_name(self, snapshot):
+        return "share-%s-manila" % snapshot["share_id"]
+
+    def _make_share_name(self, manila_share):
+        return "share-%s-manila" % manila_share["id"]
+
+    def _get_full_nfs_export_path(self, export_path):
+        subnet_ip = self.data_address
+        return "{subnet_ip}:/{export_path}".format(
+            subnet_ip=subnet_ip, export_path=export_path
+        )
+
+    def _get_flashblade_filesystem_by_name(self, name):
+        filesys = []
+        filesys.append(name)
+        try:
+            res = self._sys.file_systems.list_file_systems(names=filesys)
+        except purity_fb.rest.ApiException as ex:
+            msg = _("Share not found on FlashBlade: %s\n") % ex
+            LOG.exception(msg)
+            raise exception.ManilaException(message=msg)
+        message = "Filesystem %(share_name)s exists. Continuing..."
+        LOG.debug(message, {"share_name": res.items[0].name})
+
+    def _get_flashblade_snapshot_by_name(self, name):
+        try:
+            self._sys.file_system_snapshots.list_file_system_snapshots(
+                filter=name
+            )
+        except purity_fb.rest.ApiException as ex:
+            msg = _("Snapshot not found on FlashBlade: %s\n") % ex
+            LOG.exception(msg)
+            raise exception.ManilaException(message=msg)
+
+    @purity_fb_to_manila_exceptions
+    def _create_filesystem_export(self, flashblade_filesystem):
+        flashblade_export = flashblade_filesystem.add_export(permissions=[])
+        return {
+            "path": self._get_full_nfs_export_path(
+                flashblade_export.get_export_path()
+            ),
+            "is_admin_only": False,
+            "preferred": True,
+            "metadata": {},
+        }
+
+    @purity_fb_to_manila_exceptions
+    def _resize_share(self, share, new_size):
+        dataset_name = self._make_share_name(share)
+        self._get_flashblade_filesystem_by_name(dataset_name)
+        consumed_size = (
+            self._sys.file_systems.list_file_systems(names=[dataset_name])
+            .items[0]
+            .space.virtual
+        )
+        attr = {}
+        if consumed_size >= new_size * units.Gi:
+            raise exception.ShareShrinkingPossibleDataLoss(
+                share_id=share["id"]
+            )
+        attr["provisioned"] = new_size * units.Gi
+        n_attr = purity_fb.FileSystem(**attr)
+        LOG.debug("Resizing filesystem...")
+        self._sys.file_systems.update_file_systems(
+            name=dataset_name, attributes=n_attr
+        )
+
+    def _update_nfs_access(self, share, access_rules):
+        dataset_name = self._make_share_name(share)
+        self._get_flashblade_filesystem_by_name(dataset_name)
+        nfs_rules = ""
+        rule_state = {}
+        for access in access_rules:
+            if access["access_type"] == "ip":
+                line = (
+                    access["access_to"]
+                    + "("
+                    + access["access_level"]
+                    + ",no_root_squash) "
+                )
+                rule_state[access["access_id"]] = {"state": "active"}
+                nfs_rules += line
+            else:
+                message = _(
+                    'Only "ip" access type is allowed for NFS protocol.'
+                )
+                LOG.error(message)
+                rule_state[access["access_id"]] = {"state": "error"}
+        try:
+            self._sys.file_systems.update_file_systems(
+                name=dataset_name,
+                attributes=purity_fb.FileSystem(
+                    nfs=purity_fb.NfsRule(rules=nfs_rules)
+                ),
+            )
+            message = "Set nfs rules %(nfs_rules)s for %(share_name)s"
+            LOG.debug(
+                message, {"nfs_rules": nfs_rules, "share_name": dataset_name}
+            )
+        except purity_fb.rest.ApiException as ex:
+            msg = _("Failed to set NFS access rules: %s\n") % ex
+            LOG.exception(msg)
+            raise exception.ManilaException(message=msg)
+        return rule_state
+
+    @purity_fb_to_manila_exceptions
+    def create_share(self, context, share, share_server=None):
+        """Create a share and export it based on protocol used."""
+        size = share["size"] * units.Gi
+        share_name = self._make_share_name(share)
+
+        if share["share_proto"] == "NFS":
+            flashblade_fs = purity_fb.FileSystem(
+                name=share_name,
+                provisioned=size,
+                hard_limit_enabled=True,
+                fast_remove_directory_enabled=True,
+                snapshot_directory_enabled=True,
+                nfs=purity_fb.NfsRule(
+                    v3_enabled=True, rules="", v4_1_enabled=True
+                ),
+            )
+            self._sys.file_systems.create_file_systems(flashblade_fs)
+            location = self._get_full_nfs_export_path(share_name)
+        else:
+            message = _("Unsupported share protocol: %(proto)s.") % {
+                "proto": share["share_proto"]
+            }
+            LOG.exception(message)
+            raise exception.InvalidShare(reason=message)
+        LOG.info("FlashBlade created share %(name)s", {"name": share_name})
+
+        return location
+
+    def create_snapshot(self, context, snapshot, share_server=None):
+        """Called to create a snapshot"""
+        source = []
+        flashblade_filesystem = self._make_source_name(snapshot)
+        source.append(flashblade_filesystem)
+        try:
+            self._sys.file_system_snapshots.create_file_system_snapshots(
+                sources=source, suffix=purity_fb.SnapshotSuffix(snapshot["id"])
+            )
+        except purity_fb.rest.ApiException as ex:
+            msg = (
+                _("Snapshot failed. Share not found on FlashBlade: %s\n") % ex
+            )
+            LOG.exception(msg)
+            raise exception.ManilaException(message=msg)
+
+    def delete_share(self, context, share, share_server=None):
+        """Called to delete a share"""
+        dataset_name = self._make_share_name(share)
+        try:
+            self._get_flashblade_filesystem_by_name(dataset_name)
+        except purity_fb.rest.ApiException:
+            message = (
+                "share %(dataset_name)s not found on FlashBlade, skip "
+                "delete"
+            )
+            LOG.warning(message, {"dataset_name": dataset_name})
+            return
+        self._sys.file_systems.update_file_systems(
+            name=dataset_name,
+            attributes=purity_fb.FileSystem(
+                nfs=purity_fb.NfsRule(v3_enabled=False, v4_1_enabled=False),
+                smb=purity_fb.ProtocolRule(enabled=False),
+                destroyed=True,
+            ),
+        )
+        if self.configuration.flashblade_eradicate:
+            self._sys.file_systems.delete_file_systems(name=dataset_name)
+            LOG.info(
+                "FlashBlade eradicated share %(name)s", {"name": dataset_name}
+            )
+
+    @purity_fb_to_manila_exceptions
+    def delete_snapshot(self, context, snapshot, share_server=None):
+        """Called to delete a snapshot"""
+        dataset_name = self._make_source_name(snapshot)
+        filt = "source_display_name='{0}' and suffix='{1}'".format(
+            dataset_name, snapshot["id"]
+        )
+        name = "{0}.{1}".format(dataset_name, snapshot["id"])
+        LOG.debug("FlashBlade filter %(name)s", {"name": filt})
+        try:
+            self._get_flashblade_snapshot_by_name(filt)
+        except exception.ShareResourceNotFound:
+            message = (
+                "snapshot %(snapshot)s not found on FlashBlade, skip delete"
+            )
+            LOG.warning(
+                message, {"snapshot": dataset_name + "." + snapshot["id"]}
+            )
+            return
+        self._sys.file_system_snapshots.update_file_system_snapshots(
+            name=name, attributes=purity_fb.FileSystemSnapshot(destroyed=True)
+        )
+        LOG.debug(
+            "Snapshot %(name)s deleted successfully",
+            {"name": dataset_name + "." + snapshot["id"]},
+        )
+        if self.configuration.flashblade_eradicate:
+            self._sys.file_system_snapshots.delete_file_system_snapshots(
+                name=name
+            )
+            LOG.debug(
+                "Snapshot %(name)s eradicated successfully",
+                {"name": dataset_name + "." + snapshot["id"]},
+            )
+
+    def ensure_share(self, context, share, share_server=None):
+        """Dummy - called to ensure share is exported.
+
+        All shares created on a FlashBlade are guaranteed to
+        be exported so this check is redundant
+        """
+
+    def update_access(
+        self,
+        context,
+        share,
+        access_rules,
+        add_rules,
+        delete_rules,
+        share_server=None,
+    ):
+        """Update access of share"""
+        # We will use the access_rules list to bulk update access
+        state_map = self._update_nfs_access(share, access_rules)
+        return state_map
+
+    def extend_share(self, share, new_size, share_server=None):
+        """uses resize_share to extend a share"""
+        self._resize_share(share, new_size)
+
+    def shrink_share(self, share, new_size, share_server=None):
+        """uses resize_share to shrink a share"""
+        self._resize_share(share, new_size)
+
+    @purity_fb_to_manila_exceptions
+    def revert_to_snapshot(
+        self,
+        context,
+        snapshot,
+        share_access_rules,
+        snapshot_access_rules,
+        share_server=None,
+    ):
+        dataset_name = self._make_source_name(snapshot)
+        filt = "source_display_name='{0}' and suffix='{1}'".format(
+            dataset_name, snapshot["id"]
+        )
+        LOG.debug("FlashBlade filter %(name)s", {"name": filt})
+        name = "{0}.{1}".format(dataset_name, snapshot["id"])
+        self._get_flashblade_snapshot_by_name(filt)
+        fs_attr = purity_fb.FileSystem(
+            name=dataset_name, source=purity_fb.Reference(name=name)
+        )
+        try:
+            self._sys.file_systems.create_file_systems(
+                overwrite=True,
+                discard_non_snapshotted_data=True,
+                file_system=fs_attr,
+            )
+        except purity_fb.rest.ApiException as ex:
+            msg = _("Failed to revert snapshot: %s\n") % ex
+            LOG.exception(msg)
+            raise exception.ManilaException(message=msg)
diff --git a/manila/tests/share/drivers/purestorage/__init__.py b/manila/tests/share/drivers/purestorage/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/manila/tests/share/drivers/purestorage/test_flashblade.py b/manila/tests/share/drivers/purestorage/test_flashblade.py
new file mode 100644
index 0000000000..e6d44f7ebf
--- /dev/null
+++ b/manila/tests/share/drivers/purestorage/test_flashblade.py
@@ -0,0 +1,359 @@
+# Copyright 2021 Pure Storage 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.
+"""Unit tests for Pure Storage FlashBlade driver."""
+
+import sys
+from unittest import mock
+
+sys.modules["purity_fb"] = mock.Mock()
+
+from manila.common import constants
+from manila import exception
+from manila.share.drivers.purestorage import flashblade
+from manila import test
+
+
+_MOCK_SHARE_ID = 1
+_MOCK_SNAPSHOT_ID = "snap"
+_MOCK_SHARE_SIZE = 4294967296
+
+
+def _create_mock__getitem__(mock):
+    def mock__getitem__(self, key, default=None):
+        return getattr(mock, key, default)
+
+    return mock__getitem__
+
+
+test_nfs_share = mock.Mock(
+    id=_MOCK_SHARE_ID, size=_MOCK_SHARE_SIZE, share_proto="NFS"
+)
+test_nfs_share.__getitem__ = _create_mock__getitem__(test_nfs_share)
+
+test_snapshot = mock.Mock(id=_MOCK_SNAPSHOT_ID, share=test_nfs_share)
+test_snapshot.__getitem__ = _create_mock__getitem__(test_snapshot)
+
+
+class FakePurityFBException(Exception):
+    def __init__(self, message=None, error_code=None, *args):
+        self.message = message
+        self.error_code = error_code
+        super(FakePurityFBException, self).__init__(message, error_code, *args)
+
+
+class FlashBladeDriverTestCaseBase(test.TestCase):
+    def setUp(self):
+        super(FlashBladeDriverTestCaseBase, self).setUp()
+        self.configuration = mock.Mock()
+        self.configuration.flashblade_mgmt_vip = "mockfb1"
+        self.configuration.flashblade_data_vip = "mockfb2"
+        self.configuration.flashblade_api = "api"
+        self.configuration.flashblade_eradicate = True
+
+        self.configuration.driver_handles_share_servers = False
+        self._mock_filesystem = mock.Mock()
+        self.mock_object(self.configuration, "safe_get", self._fake_safe_get)
+        self.purity_fb = self._patch(
+            "manila.share.drivers.purestorage.flashblade.purity_fb"
+        )
+
+        self.driver = flashblade.FlashBladeShareDriver(
+            configuration=self.configuration
+        )
+
+        self._sys = self._flashblade_mock()
+
+        self._sys.api_version = mock.Mock()
+
+        self._sys.arrays.list_arrays_space = mock.Mock()
+        self.purity_fb.rest.ApiException = FakePurityFBException
+        self.purity_fb.PurityFb.return_value = self._sys
+
+        self.driver.do_setup(None)
+        self.mock_object(
+            self.driver,
+            "_resize_share",
+            mock.Mock(return_value="fake_dataset"),
+        )
+        self.mock_object(
+            self.driver,
+            "_make_source_name",
+            mock.Mock(return_value="fake_dataset"),
+        )
+        self.mock_object(
+            self.driver,
+            "_get_flashblade_filesystem_by_name",
+            mock.Mock(return_value="fake_dataset"),
+        )
+        self.mock_object(
+            self.driver,
+            "_get_flashblade_snapshot_by_name",
+            mock.Mock(return_value="fake_snapshot.snap"),
+        )
+
+    def _flashblade_mock(self):
+        result = mock.Mock()
+        self._mock_filesystem = mock.Mock()
+        result.file_systems.create_file_systems.return_value = (
+            self._mock_filesystem
+        )
+        result.file_systems.update_file_systems.return_value = (
+            self._mock_filesystem
+        )
+        result.file_systems.delete_file_systems.return_value = (
+            self._mock_filesystem
+        )
+        result.file_system_snapshots.create_file_system_snapshots\
+            .return_value = (self._mock_filesystem)
+        return result
+
+    def _raise_purity_fb(self, *args, **kwargs):
+        raise FakePurityFBException()
+
+    def _fake_safe_get(self, value):
+        return getattr(self.configuration, value, None)
+
+    def _patch(self, path, *args, **kwargs):
+        patcher = mock.patch(path, *args, **kwargs)
+        result = patcher.start()
+        self.addCleanup(patcher.stop)
+        return result
+
+
+class FlashBladeDriverTestCase(FlashBladeDriverTestCaseBase):
+    @mock.patch("manila.share.drivers.purestorage.flashblade.purity_fb", None)
+    def test_no_purity_fb_module(self):
+        self.assertRaises(exception.ManilaException,
+                          self.driver.do_setup, None)
+
+    def test_no_auth_parameters(self):
+        self.configuration.flashblade_api = None
+        self.assertRaises(
+            exception.BadConfigurationException, self.driver.do_setup, None
+        )
+
+    def test_empty_auth_parameters(self):
+        self.configuration.flashblade_api = ""
+        self.assertRaises(
+            exception.BadConfigurationException, self.driver.do_setup, None
+        )
+
+    def test_create_share_incorrect_protocol(self):
+        test_nfs_share.share_proto = "CIFS"
+        self.assertRaises(
+            exception.InvalidShare,
+            self.driver.create_share,
+            None,
+            test_nfs_share,
+        )
+
+    def test_create_nfs_share(self):
+        location = self.driver.create_share(None, test_nfs_share)
+        self._sys.file_systems.create_file_systems.assert_called_once_with(
+            self.purity_fb.FileSystem(
+                name="share-%s-manila" % test_nfs_share["id"],
+                provisioned=test_nfs_share["size"],
+                hard_limit_enabled=True,
+                fast_remove_directory_enabled=True,
+                snapshot_directory_enabled=True,
+                nfs=self.purity_fb.NfsRule(
+                    v3_enabled=True, rules="", v4_1_enabled=True
+                ),
+            )
+        )
+        self.assertEqual("mockfb2:/share-1-manila", location)
+
+    def test_delete_share(self):
+        self.mock_object(self.driver, "_get_flashblade_filesystem_by_name")
+
+        self.driver.delete_share(None, test_nfs_share)
+
+        share_name = "share-%s-manila" % test_nfs_share["id"]
+        self.driver._get_flashblade_filesystem_by_name.assert_called_once_with(
+            share_name
+        )
+        self._sys.file_systems.update_file_systems.assert_called_once_with(
+            name=share_name,
+            attributes=self.purity_fb.FileSystem(
+                nfs=self.purity_fb.NfsRule(
+                    v3_enabled=False, v4_1_enabled=False
+                ),
+                smb=self.purity_fb.ProtocolRule(enabled=False),
+                destroyed=True,
+            ),
+        )
+        self._sys.file_systems.delete_file_systems.assert_called_once_with(
+            name=share_name
+        )
+
+    def test_delete_share_no_eradicate(self):
+        self.configuration.flashblade_eradicate = False
+        self.mock_object(self.driver, "_get_flashblade_filesystem_by_name")
+
+        self.driver.delete_share(None, test_nfs_share)
+
+        share_name = "share-%s-manila" % test_nfs_share["id"]
+        self.driver._get_flashblade_filesystem_by_name.assert_called_once_with(
+            share_name
+        )
+        self._sys.file_systems.update_file_systems.assert_called_once_with(
+            name=share_name,
+            attributes=self.purity_fb.FileSystem(
+                nfs=self.purity_fb.NfsRule(
+                    v3_enabled=False, v4_1_enabled=False
+                ),
+                smb=self.purity_fb.ProtocolRule(enabled=False),
+                destroyed=True,
+            ),
+        )
+        assert not self._sys.file_systems.delete_file_systems.called
+
+    def test_delete_share_not_found(self):
+        self.mock_object(
+            self.driver,
+            "_get_flashblade_filesystem_by_name",
+            mock.Mock(side_effect=self.purity_fb.rest.ApiException),
+        )
+        mock_result = self.driver.delete_share(None, test_nfs_share)
+        self.assertIsNone(mock_result)
+
+    def test_extend_share(self):
+        self.driver.extend_share(test_nfs_share, _MOCK_SHARE_SIZE * 2)
+        self.driver._resize_share.assert_called_once_with(
+            test_nfs_share,
+            _MOCK_SHARE_SIZE * 2,
+        )
+
+    def test_shrink_share(self):
+        self.driver.shrink_share(test_nfs_share, _MOCK_SHARE_SIZE / 2)
+        self.driver._resize_share.assert_called_once_with(
+            test_nfs_share,
+            _MOCK_SHARE_SIZE / 2,
+        )
+
+    def test_shrink_share_over_consumed(self):
+        self.mock_object(
+            self.driver,
+            "_resize_share",
+            mock.Mock(
+                side_effect=exception.ShareShrinkingPossibleDataLoss(
+                    share_id=test_nfs_share["id"]
+                )
+            ),
+        )
+        self.assertRaises(
+            exception.ShareShrinkingPossibleDataLoss,
+            self.driver.shrink_share,
+            test_nfs_share,
+            _MOCK_SHARE_SIZE / 2,
+        )
+
+    def test_create_snapshot(self):
+        self.mock_object(self.driver, "_get_flashblade_filesystem_by_name")
+        self.mock_object(self.driver, "_get_flashblade_snapshot_by_name")
+        self.mock_object(self.driver, "_make_source_name")
+        self.driver.create_snapshot(None, test_snapshot)
+        self._sys.file_system_snapshots.create_file_system_snapshots\
+            .assert_called_once_with(
+                suffix=self.purity_fb.SnapshotSuffix(test_snapshot["id"]),
+                sources=[mock.ANY],
+            )
+
+    def test_delete_snapshot_no_eradicate(self):
+        self.configuration.flashblade_eradicate = False
+        self.mock_object(self.driver, "_get_flashblade_snapshot_by_name")
+        self.driver.delete_snapshot(None, test_snapshot)
+        self._sys.file_system_snapshots.update_file_system_snapshots\
+            .assert_called_once_with(
+                name=mock.ANY,
+                attributes=self.purity_fb.FileSystemSnapshot(destroyed=True),
+            )
+        assert not self._sys.file_system_snapshots\
+            .delete_file_system_snapshots.called
+
+    def test_delete_snapshot(self):
+        self.mock_object(self.driver, "_get_flashblade_snapshot_by_name")
+        self.driver.delete_snapshot(None, test_snapshot)
+        self._sys.file_system_snapshots.update_file_system_snapshots\
+            .assert_called_once_with(
+                name=mock.ANY,
+                attributes=self.purity_fb.FileSystemSnapshot(destroyed=True),
+            )
+        self._sys.file_system_snapshots.delete_file_system_snapshots\
+            .assert_called_once_with(
+                name=mock.ANY
+            )
+
+    def test_delete_snapshot_not_found(self):
+        self.mock_object(
+            self.driver,
+            "_get_flashblade_snapshot_by_name",
+            mock.Mock(
+                side_effect=exception.ShareResourceNotFound(
+                    share_id=test_nfs_share["id"]
+                )
+            ),
+        )
+        mock_result = self.driver.delete_snapshot(None, test_snapshot)
+        self.assertIsNone(mock_result)
+
+    def test_update_access_share(self):
+        access_rules = [
+            {
+                "access_level": constants.ACCESS_LEVEL_RO,
+                "access_to": "1.2.3.4",
+                "access_type": "ip",
+                "access_id": "09960614-8574-4e03-89cf-7cf267b0bd09",
+            },
+            {
+                "access_level": constants.ACCESS_LEVEL_RW,
+                "access_to": "1.2.3.5",
+                "access_type": "user",
+                "access_id": "09960614-8574-4e03-89cf-7cf267b0bd08",
+            },
+        ]
+
+        expected_rule_map = {
+            "09960614-8574-4e03-89cf-7cf267b0bd08": {"state": "error"},
+            "09960614-8574-4e03-89cf-7cf267b0bd09": {"state": "active"},
+        }
+
+        rule_map = self.driver.update_access(
+            None, test_nfs_share, access_rules, [], []
+        )
+        self.assertEqual(expected_rule_map, rule_map)
+
+    def test_revert_to_snapshot_bad_snapshot(self):
+        self.mock_object(
+            self.driver,
+            "_get_flashblade_filesystem_by_name",
+            mock.Mock(side_effect=self.purity_fb.rest.ApiException),
+        )
+        mock_result = self.driver.revert_to_snapshot(
+            None, test_snapshot, None, None
+        )
+        self.assertIsNone(mock_result)
+
+    def test_revert_to_snapshot(self):
+        self.mock_object(self.driver, "_get_flashblade_snapshot_by_name")
+        self.driver.revert_to_snapshot(None, test_snapshot, [], [])
+        self._sys.file_systems.create_file_systems.assert_called_once_with(
+            overwrite=True,
+            discard_non_snapshotted_data=True,
+            file_system=self.purity_fb.FileSystem(
+                name=test_nfs_share,
+                source=self.purity_fb.Reference(name=mock.ANY),
+            ),
+        )
diff --git a/releasenotes/notes/add-flashblade-driver-de20b758a8ce2640.yaml b/releasenotes/notes/add-flashblade-driver-de20b758a8ce2640.yaml
new file mode 100644
index 0000000000..eaab9cc335
--- /dev/null
+++ b/releasenotes/notes/add-flashblade-driver-de20b758a8ce2640.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Added Pure Storage FlashBlade driver.
+    Driver supports NFS protocol.
+    Share operations include create, delete, resize, snapshot and revert-to-snapshot.