Merge "Dell PowerScale: Rename Isilon to PowerScale in Manila Driver"

This commit is contained in:
Zuul
2025-08-12 15:57:44 +00:00
committed by Gerrit Code Review
18 changed files with 470 additions and 410 deletions

View File

@@ -0,0 +1 @@
RedirectMatch 301 ^/drivers/emc-isilon-driver.html$ /drivers/dell-emc-powerscale-driver.html

View File

@@ -14,31 +14,31 @@
License for the specific language governing permissions and limitations License for the specific language governing permissions and limitations
under the License. under the License.
Isilon Driver PowerScale Driver
============= =================
The EMC manila driver framework (EMCShareDriver) utilizes EMC storage products The EMC manila driver framework (EMCShareDriver) utilizes Dell storage products
to provide shared filesystems to OpenStack. The EMC manila driver is a plugin to provide shared filesystems to OpenStack. The EMC manila driver is a plugin
based driver which is designed to use different plugins to manage different EMC based driver which is designed to use different plugins to manage different
storage products. Dell storage products.
The Isilon manila driver is a plugin for the EMC manila driver framework which The PowerScale manila driver is a plugin for the EMC manila driver framework
allows manila to interface with an Isilon backend to provide a shared which allows manila to interface with an PowerScale backend to provide a shared
filesystem. The EMC driver framework with the Isilon plugin is referred to as filesystem. The EMC driver framework with the PowerScale plugin is referred to
the "Isilon Driver" in this document. as the "PowerScale Driver" in this document.
This Isilon Driver interfaces with an Isilon cluster via the REST Isilon This PowerScale Driver interfaces with an PowerScale cluster via the REST
Platform API (PAPI) and the RESTful Access to Namespace API (RAN). PowerScale Platform API (PAPI) and the RESTful Access to Namespace API (RAN).
Requirements Requirements
------------ ------------
- Isilon cluster running OneFS 7.2 or higher - PowerScale cluster running OneFS 9.10 or higher
Supported Operations Supported Operations
-------------------- --------------------
The following operations are supported on an Isilon cluster: The following operations are supported on an PowerScale cluster:
* Create CIFS/NFS Share * Create CIFS/NFS Share
* Delete CIFS/NFS Share * Delete CIFS/NFS Share
@@ -55,24 +55,24 @@ Backend Configuration
--------------------- ---------------------
The following parameters need to be configured in the manila configuration file The following parameters need to be configured in the manila configuration file
for the Isilon driver: for the PowerScale driver:
* share_driver = manila.share.drivers.dell_emc.driver.EMCShareDriver * share_driver = manila.share.drivers.dell_emc.driver.EMCShareDriver
* driver_handles_share_servers = False * driver_handles_share_servers = False
* emc_share_backend = isilon * emc_share_backend = powerscale
* emc_nas_server = <IP address of Isilon cluster> * emc_nas_server = <IP address of PowerScale cluster>
* emc_nas_server_port = <port to use for Isilon cluster (optional)> * emc_nas_server_port = <port to use for PowerScale cluster (optional)>
* emc_nas_login = <username> * emc_nas_login = <username>
* emc_nas_password = <password> * emc_nas_password = <password>
* emc_nas_root_dir = <root directory path to create shares (e.g./ifs/manila)> * emc_nas_root_dir = <root directory path to create shares (e.g./ifs/manila)>
Restart of :term:`manila-share` service is needed for the configuration changes to take Restart of :term:`manila-share` service is needed for the configuration changes
effect. to take effect.
Restrictions Restrictions
------------ ------------
The Isilon driver has the following restrictions: The PowerScale driver has the following restrictions:
- Only IP access type is supported for NFS and CIFS. - Only IP access type is supported for NFS and CIFS.
@@ -87,10 +87,10 @@ The :mod:`manila.share.drivers.dell_emc.driver` Module
:undoc-members: :undoc-members:
:show-inheritance: :show-inheritance:
The :mod:`manila.share.drivers.dell_emc.plugins.isilon.isilon` Module The :mod:`manila.share.drivers.dell_emc.plugins.powerscale.powerscale` Module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. automodule:: manila.share.drivers.dell_emc.plugins.isilon.isilon .. automodule:: manila.share.drivers.dell_emc.plugins.powerscale.powerscale
:noindex: :noindex:
:members: :members:
:undoc-members: :undoc-members:

View File

@@ -86,8 +86,8 @@ each back end.
container_driver container_driver
zfs_on_linux_driver zfs_on_linux_driver
netapp_cluster_mode_driver netapp_cluster_mode_driver
emc_isilon_driver
emc_vnx_driver emc_vnx_driver
dell_emc_powerscale_driver
../configuration/shared-file-systems/drivers/dell-emc-unity-driver ../configuration/shared-file-systems/drivers/dell-emc-unity-driver
../configuration/shared-file-systems/drivers/dell-emc-powerstore-driver ../configuration/shared-file-systems/drivers/dell-emc-powerstore-driver
../configuration/shared-file-systems/drivers/dell-emc-powerflex-driver ../configuration/shared-file-systems/drivers/dell-emc-powerflex-driver

View File

@@ -43,17 +43,17 @@ Mapping of share drivers and share features support
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| NetApp Clustered Data ONTAP | J | L | L | L | J |same pool (J), across back ends (U)| N | O | \- | | NetApp Clustered Data ONTAP | J | L | L | L | J |same pool (J), across back ends (U)| N | O | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| Dell EMC PowerMax | O | \- | O | \- | O | O | \- | \- | \- | | Dell PowerMax | O | \- | O | \- | O | O | \- | \- | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| EMC VNX | J | \- | \- | \- | J | J | \- | \- | \- | | Dell VNX | J | \- | \- | \- | J | J | \- | \- | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| EMC Unity | N | U | N | S | N | N | U | S | \- | | Dell Unity | N | U | N | S | N | N | U | S | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| EMC Isilon | K | \- | M | \- | K | K | \- | \- | \- | | Dell PowerScale | K | \- | M | \- | K | K | \- | \- | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| Dell EMC PowerStore | B | \- | B | B | B | B | \- | B | \- | | Dell PowerStore | B | \- | B | B | B | B | \- | B | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| Dell EMC PowerFlex | B | \- | B | \- | B | \- | \- | \- | \- | | Dell PowerFlex | B | \- | B | \- | B | \- | \- | \- | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| GlusterFS | J | \- | directory layout (T) | directory layout (T) | volume layout (L) | volume layout (L) | \- | \- | \- | | GlusterFS | J | \- | directory layout (T) | directory layout (T) | volume layout (L) | volume layout (L) | \- | \- | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+ +----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
@@ -122,17 +122,17 @@ Mapping of share drivers and share access rules support
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| NetApp Clustered Data ONTAP | NFS (J) | NFS (Q) | CIFS (J) | \- | \- | NFS (K) | NFS (Q) | CIFS (M) | \- | \- | | NetApp Clustered Data ONTAP | NFS (J) | NFS (Q) | CIFS (J) | \- | \- | NFS (K) | NFS (Q) | CIFS (M) | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| Dell EMC PowerMax | NFS (O) | NFS (R) | CIFS (O) | \- | \- | NFS (O) | NFS (R) | CIFS (O) | \- | \- | | Dell PowerMax | NFS (O) | NFS (R) | CIFS (O) | \- | \- | NFS (O) | NFS (R) | CIFS (O) | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| EMC VNX | NFS (J) | NFS (Q) | CIFS (J) | \- | \- | NFS (L) | NFS (Q) | CIFS (L) | \- | \- | | Dell VNX | NFS (J) | NFS (Q) | CIFS (J) | \- | \- | NFS (L) | NFS (Q) | CIFS (L) | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| EMC Unity | NFS (N) | NFS (Q) | CIFS (N) | \- | \- | NFS (N) | NFS (Q) | CIFS (N) | \- | \- | | Dell Unity | NFS (N) | NFS (Q) | CIFS (N) | \- | \- | NFS (N) | NFS (Q) | CIFS (N) | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| EMC Isilon | NFS,CIFS (K) | NFS (F) | CIFS (M) | \- | \- | NFS (M) | \- | CIFS (M) | \- | \- | | Dell PowerScale | NFS,CIFS (K) | \- | CIFS (M) | \- | \- | NFS (M) | \- | CIFS (M) | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| Dell EMC PowerStore | NFS (B) | \- | CIFS (B) | \- | \- | NFS (B) | \- | CIFS (B) | \- | \- | | Dell PowerStore | NFS (B) | \- | CIFS (B) | \- | \- | NFS (B) | \- | CIFS (B) | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| Dell EMC PowerFlex | NFS (B) | \- | \- | \- | \- | NFS (B) | \- | \- | \- | \- | | Dell PowerFlex | NFS (B) | \- | \- | \- | \- | NFS (B) | \- | \- | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| GlusterFS | NFS (J) | \- | \- | \- | \- | \- | \- | \- | \- | \- | | GlusterFS | NFS (J) | \- | \- | \- | \- | \- | \- | \- | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+ +----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
@@ -199,17 +199,17 @@ Mapping of share drivers and security services support
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| NetApp Clustered Data ONTAP | J | J | J | | NetApp Clustered Data ONTAP | J | J | J |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| Dell EMC PowerMax | O | \- | \- | | Dell PowerMax | O | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| EMC VNX | J | \- | \- | | Dell VNX | J | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| EMC Unity | N | \- | \- | | Dell Unity | N | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| EMC Isilon | \- | \- | \- | | EMC PowerScale | \- | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| Dell EMC PowerStore | B | \- | \- | | Dell PowerStore | B | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| Dell EMC PowerFlex | \- | \- | \- | | Dell PowerFlex | \- | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
| GlusterFS | \- | \- | \- | | GlusterFS | \- | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+ +----------------------------------------+------------------+-----------------+------------------+
@@ -278,17 +278,17 @@ More information: :ref:`capabilities_and_extra_specs`
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| NetApp Clustered Data ONTAP | J | K | M | M | M | L | P | J | O | \- | P | Q | \- | Y | | NetApp Clustered Data ONTAP | J | K | M | M | M | L | P | J | O | \- | P | Q | \- | Y |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| Dell EMC PowerMax | O | \- | \- | \- | \- | \- | \- | O | \- | \- | P | R | \- | \- | | Dell PowerMax | O | \- | \- | \- | \- | \- | \- | O | \- | \- | P | R | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| EMC VNX | J | \- | \- | \- | \- | L | \- | J | \- | \- | P | Q | \- | \- | | Dell VNX | J | \- | \- | \- | \- | L | \- | J | \- | \- | P | Q | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| EMC Unity | N | T | \- | \- | N | \- | \- | N | S | \- | P | Q | \- | \- | | Dell Unity | N | T | \- | \- | N | \- | \- | N | S | \- | P | Q | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| EMC Isilon | \- | K | \- | \- | F | \- | \- | K | \- | \- | P | \- | \- | \- | | Dell PowerScale | \- | K | \- | \- | \- | L | \- | K | \- | \- | P | \- | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| Dell EMC PowerStore | \- | B | \- | \- | B | \- | \- | B | B | \- | B | \- | \- | \- | | Dell PowerStore | \- | B | \- | \- | B | \- | \- | B | B | \- | B | \- | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| Dell EMC PowerFlex | \- | B | \- | \- | B | \- | \- | \- | \- | \- | B | \- | \- | \- | | Dell PowerFlex | \- | B | \- | \- | B | \- | \- | \- | \- | \- | B | \- | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| GlusterFS | \- | J | \- | \- | \- | L | \- | volume layout (L) | \- | \- | P | \- | \- | \- | | GlusterFS | \- | J | \- | \- | \- | L | \- | volume layout (L) | \- | \- | P | \- | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+

View File

@@ -87,7 +87,6 @@ master_doc = 'index'
# General information about the project. # General information about the project.
copyright = '2010-present, Manila contributors' copyright = '2010-present, Manila contributors'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
# language = None # language = None
@@ -175,6 +174,9 @@ html_theme_options = {
# so a file named "default.css" will overwrite the builtin "default.css". # so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static'] # html_static_path = ['_static']
# Add any paths that contain "extra" files, such as .htaccess.
html_extra_path = ['_extra']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format. # using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y' # html_last_updated_fmt = '%b %d, %Y'
@@ -213,7 +215,6 @@ html_theme_options = {
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'maniladoc' htmlhelp_basename = 'maniladoc'
# -- Options for LaTeX output ------------------------------------------------- # -- Options for LaTeX output -------------------------------------------------
# The paper size ('letter' or 'a4'). # The paper size ('letter' or 'a4').

View File

@@ -23,7 +23,7 @@ Share drivers
drivers/lvm-driver.rst drivers/lvm-driver.rst
drivers/zfs-on-linux-driver.rst drivers/zfs-on-linux-driver.rst
drivers/zfssa-manila-driver.rst drivers/zfssa-manila-driver.rst
drivers/emc-isilon-driver.rst drivers/dell-emc-powerscale-driver.rst
drivers/hitachi-hnas-driver.rst drivers/hitachi-hnas-driver.rst
drivers/hitachi-hsp-driver.rst drivers/hitachi-hsp-driver.rst
drivers/hpe-3par-share-driver.rst drivers/hpe-3par-share-driver.rst

View File

@@ -276,7 +276,7 @@ The following parameters need to be configured in the
- `emc_share_backend` - `emc_share_backend`
The plug-in name. Set it to ``powermax`` for the PowerMax driver. The plug-in name. Set it to ``powermax`` for the PowerMax driver.
Other values are ``isilon``, ``vnx`` and ``unity``. Other values are ``powerscale``, ``vnx`` and ``unity``.
- `emc_nas_server` - `emc_nas_server`
The control station IP address of the PowerMax system to be managed. The control station IP address of the PowerMax system to be managed.

View File

@@ -1,18 +1,19 @@
================= ======================
EMC Isilon driver Dell PowerScale driver
================= ======================
The EMC Shared File Systems driver framework (EMCShareDriver) utilizes The EMC Shared File Systems driver framework (EMCShareDriver) utilizes
EMC storage products to provide shared file systems to OpenStack. The Dell storage products to provide shared file systems to OpenStack. The
EMC driver is a plug-in based driver which is designed to use different EMC driver is a plug-in based driver which is designed to use different
plug-ins to manage different EMC storage products. plug-ins to manage different Dell storage products.
The Isilon driver is a plug-in for the EMC framework which allows the The PowerScale driver is a plug-in for the EMC framework which allows the
Shared File Systems service to interface with an Isilon back end to Shared File Systems service to interface with an PowerScale back end to
provide a shared filesystem. The EMC driver framework with the Isilon provide a shared filesystem. The EMC driver framework with the PowerScale
plug-in is referred to as the ``Isilon Driver`` in this document. plug-in is referred to as the ``PowerScale Driver`` in this document.
This Isilon Driver interfaces with an Isilon cluster via the REST Isilon This PowerScale Driver interfaces with an PowerScale cluster via the REST
PowerScale
Platform API (PAPI) and the RESTful Access to Namespace API (RAN). Platform API (PAPI) and the RESTful Access to Namespace API (RAN).
Requirements Requirements
@@ -52,13 +53,13 @@ Back end configuration
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
The following parameters need to be configured in the Shared File The following parameters need to be configured in the Shared File
Systems service configuration file for the Isilon driver: Systems service configuration file for the PowerScale driver:
.. code-block:: ini .. code-block:: ini
share_driver = manila.share.drivers.emc.driver.EMCShareDriver share_driver = manila.share.drivers.emc.driver.EMCShareDriver
emc_share_backend = isilon emc_share_backend = powerscale
emc_nas_server = <IP address of Isilon cluster> emc_nas_server = <IP address of PowerScale cluster>
emc_nas_login = <username> emc_nas_login = <username>
emc_nas_password = <password> emc_nas_password = <password>
@@ -75,7 +76,7 @@ Add the parameter below to set an advisory limit.
Restrictions Restrictions
~~~~~~~~~~~~ ~~~~~~~~~~~~
The Isilon driver has the following restrictions: The PowerScale driver has the following restrictions:
- Only IP access type is supported for NFS and CIFS. - Only IP access type is supported for NFS and CIFS.

View File

@@ -55,8 +55,8 @@ import manila.share.drivers.cephfs.driver
import manila.share.drivers.container.driver import manila.share.drivers.container.driver
import manila.share.drivers.container.storage_helper import manila.share.drivers.container.storage_helper
import manila.share.drivers.dell_emc.driver import manila.share.drivers.dell_emc.driver
import manila.share.drivers.dell_emc.plugins.isilon.isilon
import manila.share.drivers.dell_emc.plugins.powermax.connection import manila.share.drivers.dell_emc.plugins.powermax.connection
import manila.share.drivers.dell_emc.plugins.powerscale.powerscale
import manila.share.drivers.generic import manila.share.drivers.generic
import manila.share.drivers.glusterfs import manila.share.drivers.glusterfs
import manila.share.drivers.glusterfs.common import manila.share.drivers.glusterfs.common
@@ -95,7 +95,6 @@ import manila.volume
import manila.volume.cinder import manila.volume.cinder
import manila.wsgi.eventlet_server import manila.wsgi.eventlet_server
# List of *all* options in [DEFAULT] namespace of manila. # List of *all* options in [DEFAULT] namespace of manila.
# Any new option list or option needs to be registered here. # Any new option list or option needs to be registered here.
_global_opt_lists = [ _global_opt_lists = [

View File

@@ -42,7 +42,7 @@ EMC_NAS_OPTS = [
help='Use secure connection to server.'), help='Use secure connection to server.'),
cfg.StrOpt('emc_share_backend', cfg.StrOpt('emc_share_backend',
ignore_case=True, ignore_case=True,
choices=['isilon', 'vnx', 'unity', 'powermax', choices=['powerscale', 'isilon', 'vnx', 'unity', 'powermax',
'powerstore', 'powerflex'], 'powerstore', 'powerflex'],
help='Share backend.'), help='Share backend.'),
cfg.StrOpt('emc_nas_root_dir', cfg.StrOpt('emc_nas_root_dir',
@@ -81,6 +81,11 @@ class EMCShareDriver(driver.ShareDriver):
if self.backend_name == 'vnx': if self.backend_name == 'vnx':
LOG.warning('Dell EMC VNX share driver has been deprecated and is ' LOG.warning('Dell EMC VNX share driver has been deprecated and is '
'expected to be removed in a future release.') 'expected to be removed in a future release.')
if self.backend_name == 'isilon':
self.backend_name = 'powerscale'
LOG.warning('Dell EMC isilon share driver has been deprecated and '
'is renamed to powerscale.It is expected'
'to be removed in a future release.')
self.plugin = self.plugin_manager.load_plugin( self.plugin = self.plugin_manager.load_plugin(
self.backend_name, self.backend_name,
configuration=self.configuration) configuration=self.configuration)

View File

@@ -14,7 +14,7 @@
# under the License. # under the License.
""" """
Isilon specific NAS backend plugin. PowerScale specific NAS backend plugin.
""" """
import os import os
@@ -26,7 +26,7 @@ from manila.common import constants as const
from manila import exception from manila import exception
from manila.i18n import _ from manila.i18n import _
from manila.share.drivers.dell_emc.plugins import base from manila.share.drivers.dell_emc.plugins import base
from manila.share.drivers.dell_emc.plugins.isilon import isilon_api from manila.share.drivers.dell_emc.plugins.powerscale import powerscale_api
"""Version history: """Version history:
0.1.0 - Initial version 0.1.0 - Initial version
@@ -34,8 +34,9 @@ from manila.share.drivers.dell_emc.plugins.isilon import isilon_api
1.0.1 - Add support for update share stats 1.0.1 - Add support for update share stats
1.0.2 - Add support for ensure shares 1.0.2 - Add support for ensure shares
1.0.3 - Add support for thin provisioning 1.0.3 - Add support for thin provisioning
1.0.4 - Rename isilon to powerscale
""" """
VERSION = "1.0.3" VERSION = "1.0.4"
CONF = cfg.CONF CONF = cfg.CONF
@@ -53,11 +54,11 @@ POWERSCALE_OPTS = [
] ]
class IsilonStorageConnection(base.StorageConnection): class PowerScaleStorageConnection(base.StorageConnection):
"""Implements Isilon specific functionality for EMC Manila driver.""" """Implements PowerScale specific functionality for EMC Manila driver."""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(IsilonStorageConnection, self).__init__(*args, **kwargs) super(PowerScaleStorageConnection, self).__init__(*args, **kwargs)
LOG.debug('Setting up attributes for Manila ' LOG.debug('Setting up attributes for Manila '
'Dell PowerScale Driver.') 'Dell PowerScale Driver.')
if 'configuration' in kwargs: if 'configuration' in kwargs:
@@ -75,7 +76,7 @@ class IsilonStorageConnection(base.StorageConnection):
self._shares = {} self._shares = {}
self._snapshots = {} self._snapshots = {}
self._isilon_api = None self._powerscale_api = None
self.driver_handles_share_servers = False self.driver_handles_share_servers = False
self.ipv6_implemented = True self.ipv6_implemented = True
# props for share status update # props for share status update
@@ -104,7 +105,7 @@ class IsilonStorageConnection(base.StorageConnection):
# apply directory quota based on share size # apply directory quota based on share size
max_share_size = share['size'] * units.Gi max_share_size = share['size'] * units.Gi
self._isilon_api.quota_create( self._powerscale_api.quota_create(
self._get_container_path(share), 'directory', max_share_size) self._get_container_path(share), 'directory', max_share_size)
return location return location
@@ -118,7 +119,7 @@ class IsilonStorageConnection(base.StorageConnection):
# Clone snapshot to new location # Clone snapshot to new location
fq_target_dir = self._get_container_path(share) fq_target_dir = self._get_container_path(share)
self._isilon_api.clone_snapshot(snapshot['name'], fq_target_dir) self._powerscale_api.clone_snapshot(snapshot['name'], fq_target_dir)
return location return location
@@ -129,7 +130,7 @@ class IsilonStorageConnection(base.StorageConnection):
container_path = self._get_container_path(share) container_path = self._get_container_path(share)
self._create_directory(container_path) self._create_directory(container_path)
# Create nfs share # Create nfs share
share_created = self._isilon_api.create_nfs_export(container_path) share_created = self._powerscale_api.create_nfs_export(container_path)
if not share_created: if not share_created:
message = ( message = (
_('The requested NFS share "%(share)s" was not created.') % _('The requested NFS share "%(share)s" was not created.') %
@@ -146,7 +147,7 @@ class IsilonStorageConnection(base.StorageConnection):
container_path = self._get_container_path(share) container_path = self._get_container_path(share)
self._create_directory(container_path) self._create_directory(container_path)
# Create smb share # Create smb share
share_created = self._isilon_api.create_smb_share( share_created = self._powerscale_api.create_smb_share(
share['name'], container_path) share['name'], container_path)
if not share_created: if not share_created:
message = ( message = (
@@ -159,7 +160,7 @@ class IsilonStorageConnection(base.StorageConnection):
def _create_directory(self, path, recursive=False): def _create_directory(self, path, recursive=False):
"""Is called to create a directory.""" """Is called to create a directory."""
dir_created = self._isilon_api.create_directory(path, recursive) dir_created = self._powerscale_api.create_directory(path, recursive)
if not dir_created: if not dir_created:
message = ( message = (
_('Failed to create directory "%(dir)s".') % _('Failed to create directory "%(dir)s".') %
@@ -171,7 +172,7 @@ class IsilonStorageConnection(base.StorageConnection):
"""Is called to create snapshot.""" """Is called to create snapshot."""
LOG.debug(f'Creating snapshot {snapshot["name"]}.') LOG.debug(f'Creating snapshot {snapshot["name"]}.')
snapshot_path = os.path.join(self._root_dir, snapshot['share_name']) snapshot_path = os.path.join(self._root_dir, snapshot['share_name'])
snap_created = self._isilon_api.create_snapshot( snap_created = self._powerscale_api.create_snapshot(
snapshot['name'], snapshot_path) snapshot['name'], snapshot_path)
if not snap_created: if not snap_created:
message = ( message = (
@@ -201,10 +202,10 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_quota(self, path): def _delete_quota(self, path):
"""Is called to remove quota.""" """Is called to remove quota."""
quota = self._isilon_api.quota_get(path, 'directory') quota = self._powerscale_api.quota_get(path, 'directory')
if quota: if quota:
LOG.debug(f'Removing quota {quota["id"]}') LOG.debug(f'Removing quota {quota["id"]}')
deleted = self._isilon_api.delete_quota(quota['id']) deleted = self._powerscale_api.delete_quota(quota['id'])
if not deleted: if not deleted:
message = ( message = (
_('Failed to delete quota "%(quota_id)s" for ' _('Failed to delete quota "%(quota_id)s" for '
@@ -216,10 +217,10 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_directory(self, path): def _delete_directory(self, path):
"""Is called to remove directory.""" """Is called to remove directory."""
path_exist = self._isilon_api.is_path_existent(path) path_exist = self._powerscale_api.is_path_existent(path)
if path_exist: if path_exist:
LOG.debug(f'Removing directory {path}') LOG.debug(f'Removing directory {path}')
deleted = self._isilon_api.delete_path(path, recursive=True) deleted = self._powerscale_api.delete_path(path, recursive=True)
if not deleted: if not deleted:
message = ( message = (
_('Failed to delete directory "%(dir)s".') % _('Failed to delete directory "%(dir)s".') %
@@ -230,7 +231,7 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_nfs_share(self, share): def _delete_nfs_share(self, share):
"""Is called to remove nfs share.""" """Is called to remove nfs share."""
share_id = self._isilon_api.lookup_nfs_export( share_id = self._powerscale_api.lookup_nfs_export(
self._get_container_path(share)) self._get_container_path(share))
if share_id is None: if share_id is None:
@@ -239,7 +240,7 @@ class IsilonStorageConnection(base.StorageConnection):
LOG.warning(lw, share['name']) LOG.warning(lw, share['name'])
else: else:
# attempt to delete the share # attempt to delete the share
export_deleted = self._isilon_api.delete_nfs_share(share_id) export_deleted = self._powerscale_api.delete_nfs_share(share_id)
if not export_deleted: if not export_deleted:
message = _('Error deleting NFS share: %s') % share['name'] message = _('Error deleting NFS share: %s') % share['name']
LOG.error(message) LOG.error(message)
@@ -247,13 +248,14 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_cifs_share(self, share): def _delete_cifs_share(self, share):
"""Is called to remove CIFS share.""" """Is called to remove CIFS share."""
smb_share = self._isilon_api.lookup_smb_share(share['name']) smb_share = self._powerscale_api.lookup_smb_share(share['name'])
if smb_share is None: if smb_share is None:
lw = ('Attempted to delete CIFS Share "%s", but the share does ' lw = ('Attempted to delete CIFS Share "%s", but the share does '
'not appear to exist.') 'not appear to exist.')
LOG.warning(lw, share['name']) LOG.warning(lw, share['name'])
else: else:
share_deleted = self._isilon_api.delete_smb_share(share['name']) share_deleted = self._powerscale_api.delete_smb_share(
share['name'])
if not share_deleted: if not share_deleted:
message = _('Error deleting CIFS share: %s') % share['name'] message = _('Error deleting CIFS share: %s') % share['name']
LOG.error(message) LOG.error(message)
@@ -262,7 +264,7 @@ class IsilonStorageConnection(base.StorageConnection):
def delete_snapshot(self, context, snapshot, share_server): def delete_snapshot(self, context, snapshot, share_server):
"""Is called to remove snapshot.""" """Is called to remove snapshot."""
LOG.debug(f'Deleting snapshot {snapshot["name"]}') LOG.debug(f'Deleting snapshot {snapshot["name"]}')
deleted = self._isilon_api.delete_snapshot(snapshot['name']) deleted = self._powerscale_api.delete_snapshot(snapshot['name'])
if not deleted: if not deleted:
message = ( message = (
_('Failed to delete snapshot "%(snap)s".') % _('Failed to delete snapshot "%(snap)s".') %
@@ -280,7 +282,7 @@ class IsilonStorageConnection(base.StorageConnection):
'name': share['name'], 'size': new_size 'name': share['name'], 'size': new_size
}) })
new_quota_size = new_size * units.Gi new_quota_size = new_size * units.Gi
self._isilon_api.quota_set( self._powerscale_api.quota_set(
self._get_container_path(share), 'directory', new_quota_size) self._get_container_path(share), 'directory', new_quota_size)
def allow_access(self, context, share, access, share_server): def allow_access(self, context, share, access, share_server):
@@ -295,7 +297,7 @@ class IsilonStorageConnection(base.StorageConnection):
"""Check for setup error.""" """Check for setup error."""
def connect(self, emc_share_driver, context): def connect(self, emc_share_driver, context):
"""Connect to an Isilon cluster.""" """Connect to an PowerScale cluster."""
LOG.debug('Reading configuration parameters for Manila' LOG.debug('Reading configuration parameters for Manila'
' Dell PowerScale Driver.') ' Dell PowerScale Driver.')
config = emc_share_driver.configuration config = emc_share_driver.configuration
@@ -320,13 +322,13 @@ class IsilonStorageConnection(base.StorageConnection):
if self._verify_ssl_cert: if self._verify_ssl_cert:
self._ssl_cert_path = config.safe_get("emc_ssl_cert_path") self._ssl_cert_path = config.safe_get("emc_ssl_cert_path")
self._dir_permission = config.safe_get("powerscale_dir_permission") self._dir_permission = config.safe_get("powerscale_dir_permission")
self._isilon_api = isilon_api.IsilonApi( self._powerscale_api = powerscale_api.PowerScaleApi(
self._server_url, self._username, self._password, self._server_url, self._username, self._password,
self._verify_ssl_cert, self._ssl_cert_path, self._verify_ssl_cert, self._ssl_cert_path,
self._dir_permission, self._dir_permission,
self._threshold_limit) self._threshold_limit)
if not self._isilon_api.is_path_existent(self._root_dir): if not self._powerscale_api.is_path_existent(self._root_dir):
self._create_directory(self._root_dir, recursive=True) self._create_directory(self._root_dir, recursive=True)
# configuration for share status update # configuration for share status update
@@ -367,11 +369,11 @@ class IsilonStorageConnection(base.StorageConnection):
self.max_over_subscription_ratio, self.max_over_subscription_ratio,
'thin_provisioning': True, 'thin_provisioning': True,
} }
spaces = self._isilon_api.get_space_stats() spaces = self._powerscale_api.get_space_stats()
if spaces: if spaces:
pool_stat['total_capacity_gb'] = spaces['total'] // units.Gi pool_stat['total_capacity_gb'] = spaces['total'] // units.Gi
pool_stat['free_capacity_gb'] = spaces['free'] // units.Gi pool_stat['free_capacity_gb'] = spaces['free'] // units.Gi
allocated_space = self._isilon_api.get_allocated_space() allocated_space = self._powerscale_api.get_allocated_space()
pool_stat['allocated_capacity_gb'] = allocated_space pool_stat['allocated_capacity_gb'] = allocated_space
stats_dict['pools'] = [pool_stat] stats_dict['pools'] = [pool_stat]
@@ -415,7 +417,7 @@ class IsilonStorageConnection(base.StorageConnection):
elif rule['access_level'] == const.ACCESS_LEVEL_RO: elif rule['access_level'] == const.ACCESS_LEVEL_RO:
nfs_ro_ips.add(rule['access_to']) nfs_ro_ips.add(rule['access_to'])
export_id = self._isilon_api.lookup_nfs_export( export_id = self._powerscale_api.lookup_nfs_export(
self._get_container_path(share)) self._get_container_path(share))
if export_id is None: if export_id is None:
# share does not exist on backend (set all rules to error state) # share does not exist on backend (set all rules to error state)
@@ -424,7 +426,7 @@ class IsilonStorageConnection(base.StorageConnection):
LOG.error(message) LOG.error(message)
return rule_state_map return rule_state_map
r = self._isilon_api.modify_nfs_export_access( r = self._powerscale_api.modify_nfs_export_access(
export_id, ro_ips=list(nfs_ro_ips), rw_ips=list(nfs_rw_ips)) export_id, ro_ips=list(nfs_ro_ips), rw_ips=list(nfs_rw_ips))
if not r: if not r:
return rule_state_map return rule_state_map
@@ -449,20 +451,22 @@ class IsilonStorageConnection(base.StorageConnection):
) % {'type': rule['access_type']}) ) % {'type': rule['access_type']})
LOG.error(message) LOG.error(message)
rule_state_map.update({rule['access_id']: {'state': 'error'}}) rule_state_map.update({rule['access_id']: {'state': 'error'}})
ips = self._get_cifs_ip_list(ip_access_rules, rule_state_map) ips = self._get_cifs_ip_list(ip_access_rules, rule_state_map)
user_permissions = self._get_cifs_user_permissions( user_permissions = self._get_cifs_user_permissions(
user_access_rules, rule_state_map) user_access_rules, rule_state_map)
share_updated = self._isilon_api.modify_smb_share_access( share_updated = self._powerscale_api.modify_smb_share_access(
share['name'], share['name'],
host_acl=ips, host_acl=ips,
permissions=user_permissions) permissions=user_permissions)
if not share_updated: if not share_updated:
message = ( message = (
_('Failed to update access rules for CIFS share "%(share)s".' _(
) % {'share': share['name']}) 'Failed to update access rules for CIFS share '
'"%(share)s".'
) % {'share': share['name']}
)
LOG.error(message) LOG.error(message)
for rule in access_rules: for rule in access_rules:
rule_state_map[rule['access_id']] = { rule_state_map[rule['access_id']] = {
@@ -490,9 +494,9 @@ class IsilonStorageConnection(base.StorageConnection):
cifs_user_permissions = [] cifs_user_permissions = []
for rule in access_rules: for rule in access_rules:
if rule['access_level'] == const.ACCESS_LEVEL_RW: if rule['access_level'] == const.ACCESS_LEVEL_RW:
smb_permission = isilon_api.SmbPermission.rw smb_permission = powerscale_api.SmbPermission.rw
elif rule['access_level'] == const.ACCESS_LEVEL_RO: elif rule['access_level'] == const.ACCESS_LEVEL_RO:
smb_permission = isilon_api.SmbPermission.ro smb_permission = powerscale_api.SmbPermission.ro
else: else:
message = ('Only RW and RO access levels are supported ' message = ('Only RW and RO access levels are supported '
'for CIFS user access.') 'for CIFS user access.')
@@ -500,7 +504,7 @@ class IsilonStorageConnection(base.StorageConnection):
rule_state_map.update({rule['access_id']: {'state': 'error'}}) rule_state_map.update({rule['access_id']: {'state': 'error'}})
continue continue
user_sid = self._isilon_api.get_user_sid(rule['access_to']) user_sid = self._powerscale_api.get_user_sid(rule['access_to'])
if user_sid: if user_sid:
cifs_user_permissions.append({ cifs_user_permissions.append({
'permission': smb_permission.value, 'permission': smb_permission.value,
@@ -521,7 +525,7 @@ class IsilonStorageConnection(base.StorageConnection):
:returns: A dictionary containing driver-specific info. :returns: A dictionary containing driver-specific info.
""" """
LOG.debug("Retrieving PowerScale backend info.") LOG.debug("Retrieving PowerScale backend info.")
cluster_version = self._isilon_api.get_cluster_version() cluster_version = self._powerscale_api.get_cluster_version()
return {'driver_version': VERSION, return {'driver_version': VERSION,
'cluster_version': cluster_version, 'cluster_version': cluster_version,
'rest_server': self._server, 'rest_server': self._server,
@@ -538,7 +542,8 @@ class IsilonStorageConnection(base.StorageConnection):
for share in shares: for share in shares:
if share['share_proto'] == 'NFS': if share['share_proto'] == 'NFS':
container_path = self._get_container_path(share) container_path = self._get_container_path(share)
share_id = self._isilon_api.lookup_nfs_export(container_path) share_id = self._powerscale_api.lookup_nfs_export(
container_path)
if share_id: if share_id:
location = self._format_nfs_path(container_path) location = self._format_nfs_path(container_path)
updates[share['id']] = { updates[share['id']] = {
@@ -549,7 +554,8 @@ class IsilonStorageConnection(base.StorageConnection):
else: else:
LOG.warning(f'NFS Share {share["name"]} is not found.') LOG.warning(f'NFS Share {share["name"]} is not found.')
elif share['share_proto'] == 'CIFS': elif share['share_proto'] == 'CIFS':
smb_share = self._isilon_api.lookup_smb_share(share['name']) smb_share = self._powerscale_api.lookup_smb_share(
share['name'])
if smb_share: if smb_share:
location = self._format_smb_path(share['name']) location = self._format_smb_path(share['name'])
updates[share['id']] = { updates[share['id']] = {

View File

@@ -27,7 +27,7 @@ from manila.i18n import _
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
class IsilonApi(object): class PowerScaleApi(object):
def __init__(self, api_url, username, password, def __init__(self, api_url, username, password,
verify_ssl_cert=False, verify_ssl_cert=False,

View File

@@ -22,18 +22,18 @@ from oslo_utils import units
from manila.common import constants as const from manila.common import constants as const
from manila import exception from manila import exception
from manila.i18n import _ from manila.i18n import _
from manila.share.drivers.dell_emc.plugins.isilon import isilon from manila.share.drivers.dell_emc.plugins.powerscale import powerscale
from manila import test from manila import test
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ddt.ddt @ddt.ddt
class IsilonTest(test.TestCase): class PowerScaleTest(test.TestCase):
"""Integration test for the Isilon Manila driver.""" """Integration test for the PowerScale Manila driver."""
ISILON_ADDR = '10.0.0.1' POWERSCALE_ADDR = '10.0.0.1'
API_URL = 'https://%s:8080' % ISILON_ADDR API_URL = 'https://%s:8080' % POWERSCALE_ADDR
AUTH = ('admin', 'admin') AUTH = ('admin', 'admin')
ROOT_DIR = '/ifs/manila-test' ROOT_DIR = '/ifs/manila-test'
@@ -75,14 +75,13 @@ class IsilonTest(test.TestCase):
return None return None
@mock.patch( @mock.patch(
'manila.share.drivers.dell_emc.plugins.isilon.isilon.isilon_api.' 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.'
'IsilonApi', 'powerscale_api.PowerScaleApi', autospec=True)
autospec=True)
def setUp(self, mock_isi_api): def setUp(self, mock_isi_api):
super(IsilonTest, self).setUp() super(PowerScaleTest, self).setUp()
self._mock_isilon_api = mock_isi_api.return_value self._mock_powerscale_api = mock_isi_api.return_value
self.storage_connection = isilon.IsilonStorageConnection(LOG) self.storage_connection = powerscale.PowerScaleStorageConnection(LOG)
self.mock_context = mock.Mock('Context') self.mock_context = mock.Mock('Context')
self.mock_emc_driver = mock.Mock('EmcDriver') self.mock_emc_driver = mock.Mock('EmcDriver')
@@ -113,8 +112,8 @@ class IsilonTest(test.TestCase):
def test_create_share_nfs(self): def test_create_share_nfs(self):
share_path = self.SHARE_DIR share_path = self.SHARE_DIR
self.assertFalse(self._mock_isilon_api.create_directory.called) self.assertFalse(self._mock_powerscale_api.create_directory.called)
self.assertFalse(self._mock_isilon_api.create_nfs_export.called) self.assertFalse(self._mock_powerscale_api.create_nfs_export.called)
# create the share # create the share
share = {"name": self.SHARE_NAME, "share_proto": 'NFS', "size": 8} share = {"name": self.SHARE_NAME, "share_proto": 'NFS', "size": 8}
@@ -122,42 +121,42 @@ class IsilonTest(test.TestCase):
share, None) share, None)
# verify location and API call made # verify location and API call made
path = '%s:%s' % (self.ISILON_ADDR, self.SHARE_DIR) path = '%s:%s' % (self.POWERSCALE_ADDR, self.SHARE_DIR)
expected_location = [{'is_admin_only': False, expected_location = [{'is_admin_only': False,
'metadata': {"preferred": True}, 'metadata': {"preferred": True},
'path': path}] 'path': path}]
self.assertEqual(expected_location, location) self.assertEqual(expected_location, location)
self._mock_isilon_api.create_directory.assert_called_with( self._mock_powerscale_api.create_directory.assert_called_with(
share_path, False) share_path, False)
self._mock_isilon_api.create_nfs_export.assert_called_with(share_path) self._mock_powerscale_api.create_nfs_export.assert_called_with(
share_path)
# verify directory quota call made # verify directory quota call made
self._mock_isilon_api.quota_create.assert_called_with( self._mock_powerscale_api.quota_create.assert_called_with(
share_path, 'directory', 8 * units.Gi) share_path, 'directory', 8 * units.Gi)
def test_create_share_cifs(self): def test_create_share_cifs(self):
self.assertFalse(self._mock_isilon_api.create_directory.called) self.assertFalse(self._mock_powerscale_api.create_directory.called)
self.assertFalse(self._mock_isilon_api.create_smb_share.called) self.assertFalse(self._mock_powerscale_api.create_smb_share.called)
# create the share # create the share
share = {"name": self.SHARE_NAME, "share_proto": 'CIFS', "size": 8} share = {"name": self.SHARE_NAME, "share_proto": 'CIFS', "size": 8}
location = self.storage_connection.create_share(self.mock_context, location = self.storage_connection.create_share(self.mock_context,
share, None) share, None)
path = '\\\\{0}\\{1}'.format(self.POWERSCALE_ADDR, self.SHARE_NAME)
path = '\\\\{0}\\{1}'.format(self.ISILON_ADDR, self.SHARE_NAME)
expected_location = [{'is_admin_only': False, expected_location = [{'is_admin_only': False,
'metadata': {"preferred": True}, 'metadata': {"preferred": True},
'path': path}] 'path': path}]
self.assertEqual(expected_location, location) self.assertEqual(expected_location, location)
self._mock_isilon_api.create_directory.assert_called_once_with( self._mock_powerscale_api.create_directory.assert_called_once_with(
self.SHARE_DIR, False) self.SHARE_DIR, False)
self._mock_isilon_api.create_smb_share.assert_called_once_with( self._mock_powerscale_api.create_smb_share.assert_called_once_with(
self.SHARE_NAME, self.SHARE_DIR) self.SHARE_NAME, self.SHARE_DIR)
# verify directory quota call made # verify directory quota call made
self._mock_isilon_api.quota_create.assert_called_with( self._mock_powerscale_api.quota_create.assert_called_with(
self.SHARE_DIR, 'directory', 8 * units.Gi) self.SHARE_DIR, 'directory', 8 * units.Gi)
def test_create_share_invalid_share_protocol(self): def test_create_share_invalid_share_protocol(self):
@@ -169,7 +168,7 @@ class IsilonTest(test.TestCase):
def test_create_share_nfs_backend_failure(self): def test_create_share_nfs_backend_failure(self):
share = {"name": self.SHARE_NAME, "share_proto": 'NFS'} share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
self._mock_isilon_api.create_nfs_export.return_value = False self._mock_powerscale_api.create_nfs_export.return_value = False
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
@@ -178,7 +177,7 @@ class IsilonTest(test.TestCase):
def test_create_share_cifs_backend_failure(self): def test_create_share_cifs_backend_failure(self):
share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'} share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
self._mock_isilon_api.create_smb_share.return_value = False self._mock_powerscale_api.create_smb_share.return_value = False
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
@@ -187,7 +186,7 @@ class IsilonTest(test.TestCase):
def test_create_directory_backend_failure(self): def test_create_directory_backend_failure(self):
share = {"name": self.SHARE_NAME, "share_proto": 'NFS'} share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
self._mock_isilon_api.create_directory.return_value = False self._mock_powerscale_api.create_directory.return_value = False
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
@@ -204,14 +203,14 @@ class IsilonTest(test.TestCase):
None) None)
# verify the create snapshot API call is executed # verify the create snapshot API call is executed
self._mock_isilon_api.create_snapshot.assert_called_with(snapshot_name, self._mock_powerscale_api.create_snapshot.assert_called_with(
snapshot_path) snapshot_name, snapshot_path)
def test_create_snapshot_backend_failure(self): def test_create_snapshot_backend_failure(self):
snapshot_name = "snapshot01" snapshot_name = "snapshot01"
snapshot_path = '/ifs/home/admin' snapshot_path = '/ifs/home/admin'
snapshot = {'name': snapshot_name, 'share_name': snapshot_path} snapshot = {'name': snapshot_name, 'share_name': snapshot_path}
self._mock_isilon_api.create_snapshot.return_value = False self._mock_powerscale_api.create_snapshot.return_value = False
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
@@ -220,8 +219,8 @@ class IsilonTest(test.TestCase):
def test_create_share_from_snapshot_nfs(self): def test_create_share_from_snapshot_nfs(self):
# assertions # assertions
self.assertFalse(self._mock_isilon_api.create_nfs_export.called) self.assertFalse(self._mock_powerscale_api.create_nfs_export.called)
self.assertFalse(self._mock_isilon_api.clone_snapshot.called) self.assertFalse(self._mock_powerscale_api.clone_snapshot.called)
snapshot_name = "snapshot01" snapshot_name = "snapshot01"
snapshot_path = '/ifs/home/admin' snapshot_path = '/ifs/home/admin'
@@ -233,14 +232,14 @@ class IsilonTest(test.TestCase):
self.mock_context, share, snapshot, None) self.mock_context, share, snapshot, None)
# verify NFS export created at expected location # verify NFS export created at expected location
self._mock_isilon_api.create_nfs_export.assert_called_with( self._mock_powerscale_api.create_nfs_export.assert_called_with(
self.SHARE_DIR) self.SHARE_DIR)
# verify clone_directory(container_path) method called # verify clone_directory(container_path) method called
self._mock_isilon_api.clone_snapshot.assert_called_once_with( self._mock_powerscale_api.clone_snapshot.assert_called_once_with(
snapshot_name, self.SHARE_DIR) snapshot_name, self.SHARE_DIR)
path = '{0}:{1}'.format( path = '{0}:{1}'.format(
self.ISILON_ADDR, self.SHARE_DIR) self.POWERSCALE_ADDR, self.SHARE_DIR)
expected_location = {'is_admin_only': False, expected_location = {'is_admin_only': False,
'metadata': {"preferred": True}, 'metadata': {"preferred": True},
'path': path} 'path': path}
@@ -248,13 +247,13 @@ class IsilonTest(test.TestCase):
self.assertEqual(expected_location, location[0]) self.assertEqual(expected_location, location[0])
# verify directory quota call made # verify directory quota call made
self._mock_isilon_api.quota_create.assert_called_with( self._mock_powerscale_api.quota_create.assert_called_with(
self.SHARE_DIR, 'directory', 5 * units.Gi) self.SHARE_DIR, 'directory', 5 * units.Gi)
def test_create_share_from_snapshot_cifs(self): def test_create_share_from_snapshot_cifs(self):
# assertions # assertions
self.assertFalse(self._mock_isilon_api.create_smb_share.called) self.assertFalse(self._mock_powerscale_api.create_smb_share.called)
self.assertFalse(self._mock_isilon_api.clone_snapshot.called) self.assertFalse(self._mock_powerscale_api.clone_snapshot.called)
# setup # setup
snapshot_name = "snapshot01" snapshot_name = "snapshot01"
snapshot_path = '/ifs/home/admin' snapshot_path = '/ifs/home/admin'
@@ -267,11 +266,11 @@ class IsilonTest(test.TestCase):
self.mock_context, share, snapshot, None) self.mock_context, share, snapshot, None)
# verify call made to create new CIFS share # verify call made to create new CIFS share
self._mock_isilon_api.create_smb_share.assert_called_once_with( self._mock_powerscale_api.create_smb_share.assert_called_once_with(
new_share_name, self.CLONE_DIR) new_share_name, self.CLONE_DIR)
self._mock_isilon_api.clone_snapshot.assert_called_once_with( self._mock_powerscale_api.clone_snapshot.assert_called_once_with(
snapshot_name, self.CLONE_DIR) snapshot_name, self.CLONE_DIR)
path = '\\\\{0}\\{1}'.format(self.ISILON_ADDR, new_share_name) path = '\\\\{0}\\{1}'.format(self.POWERSCALE_ADDR, new_share_name)
expected_location = {'is_admin_only': False, expected_location = {'is_admin_only': False,
'metadata': {"preferred": True}, 'metadata': {"preferred": True},
'path': path} 'path': path}
@@ -279,34 +278,36 @@ class IsilonTest(test.TestCase):
# verify directory quota call made # verify directory quota call made
expected_share_path = '{0}/{1}'.format(self.ROOT_DIR, new_share_name) expected_share_path = '{0}/{1}'.format(self.ROOT_DIR, new_share_name)
self._mock_isilon_api.quota_create.assert_called_with( self._mock_powerscale_api.quota_create.assert_called_with(
expected_share_path, 'directory', 2 * units.Gi) expected_share_path, 'directory', 2 * units.Gi)
def test_delete_share_nfs(self): def test_delete_share_nfs(self):
share = {"name": self.SHARE_NAME, "share_proto": 'NFS'} share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
fake_share_num = 42 fake_share_num = 42
self._mock_isilon_api.lookup_nfs_export.return_value = fake_share_num self._mock_powerscale_api.lookup_nfs_export.return_value = (
self.assertFalse(self._mock_isilon_api.delete_nfs_share.called) fake_share_num)
self.assertFalse(self._mock_powerscale_api.delete_nfs_share.called)
# delete the share # delete the share
self.storage_connection.delete_share(self.mock_context, share, None) self.storage_connection.delete_share(self.mock_context, share, None)
# verify share delete # verify share delete
self._mock_isilon_api.delete_nfs_share.assert_called_with( self._mock_powerscale_api.delete_nfs_share.assert_called_with(
fake_share_num) fake_share_num)
def test_delete_share_cifs(self): def test_delete_share_cifs(self):
self.assertFalse(self._mock_isilon_api.delete_smb_share.called) self.assertFalse(self._mock_powerscale_api.delete_smb_share.called)
# delete the share # delete the share
share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'} share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
self.storage_connection.delete_share(self.mock_context, share, None) self.storage_connection.delete_share(self.mock_context, share, None)
# verify share deleted # verify share deleted
self._mock_isilon_api.delete_smb_share.assert_called_with( self._mock_powerscale_api.delete_smb_share.assert_called_with(
self.SHARE_NAME) self.SHARE_NAME)
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.isilon.LOG') @mock.patch(
'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG')
def test_delete_share_invalid_share_proto(self, mock_log): def test_delete_share_invalid_share_proto(self, mock_log):
share = {"name": self.SHARE_NAME, "share_proto": 'FOO_PROTOCOL'} share = {"name": self.SHARE_NAME, "share_proto": 'FOO_PROTOCOL'}
@@ -317,7 +318,7 @@ class IsilonTest(test.TestCase):
def test_delete_nfs_share_backend_failure(self): def test_delete_nfs_share_backend_failure(self):
share = {"name": self.SHARE_NAME, "share_proto": 'NFS'} share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
self._mock_isilon_api.delete_nfs_share.return_value = False self._mock_powerscale_api.delete_nfs_share.return_value = False
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
self.storage_connection.delete_share, self.storage_connection.delete_share,
@@ -325,7 +326,7 @@ class IsilonTest(test.TestCase):
) )
def test_delete_nfs_share_share_does_not_exist(self): def test_delete_nfs_share_share_does_not_exist(self):
self._mock_isilon_api.lookup_nfs_export.return_value = None self._mock_powerscale_api.lookup_nfs_export.return_value = None
share = {"name": self.SHARE_NAME, "share_proto": 'NFS'} share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
# verify the calling delete on a non-existent share returns and does # verify the calling delete on a non-existent share returns and does
@@ -335,7 +336,7 @@ class IsilonTest(test.TestCase):
def test_delete_cifs_share_backend_failure(self): def test_delete_cifs_share_backend_failure(self):
share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'} share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
self._mock_isilon_api.delete_smb_share.return_value = False self._mock_powerscale_api.delete_smb_share.return_value = False
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
self.storage_connection.delete_share, self.storage_connection.delete_share,
@@ -344,37 +345,43 @@ class IsilonTest(test.TestCase):
def test_delete_cifs_share_share_does_not_exist(self): def test_delete_cifs_share_share_does_not_exist(self):
share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'} share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
self._mock_isilon_api.lookup_smb_share.return_value = None self._mock_powerscale_api.lookup_smb_share.return_value = None
# verify the calling delete on a non-existent share returns and does # verify the calling delete on a non-existent share returns and does
# not throw exception # not throw exception
self.storage_connection.delete_share(self.mock_context, share, None) self.storage_connection.delete_share(self.mock_context, share, None)
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.isilon.LOG') @mock.patch(
'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
)
def test_delete_quota_success(self, mock_log): def test_delete_quota_success(self, mock_log):
path = '/path/to/quota' path = '/path/to/quota'
quota_id = '123' quota_id = '123'
quota_data = {'id': quota_id} quota_data = {'id': quota_id}
self._mock_isilon_api.quota_get.return_value = quota_data self._mock_powerscale_api.quota_get.return_value = quota_data
self._mock_isilon_api.delete_quota.return_value = True self._mock_powerscale_api.delete_quota.return_value = True
self.storage_connection._delete_quota(path) self.storage_connection._delete_quota(path)
self._mock_isilon_api.quota_get.assert_called_once_with( self._mock_powerscale_api.quota_get.assert_called_once_with(
path, 'directory') path, 'directory')
self._mock_isilon_api.delete_quota.assert_called_once_with(quota_id) self._mock_powerscale_api.delete_quota.assert_called_once_with(
quota_id)
mock_log.debug.assert_called_once_with(f'Removing quota {quota_id}') mock_log.debug.assert_called_once_with(f'Removing quota {quota_id}')
mock_log.warning.assert_not_called() mock_log.warning.assert_not_called()
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.isilon.LOG') @mock.patch(
'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
)
def test_delete_quota_failure(self, mock_log): def test_delete_quota_failure(self, mock_log):
path = '/path/to/quota' path = '/path/to/quota'
quota_id = '123' quota_id = '123'
quota_data = {'id': quota_id} quota_data = {'id': quota_id}
self._mock_isilon_api.quota_get.return_value = quota_data self._mock_powerscale_api.quota_get.return_value = quota_data
self._mock_isilon_api.delete_quota.return_value = False self._mock_powerscale_api.delete_quota.return_value = False
self.storage_connection._delete_quota(path) self.storage_connection._delete_quota(path)
self._mock_isilon_api.quota_get.assert_called_once_with( self._mock_powerscale_api.quota_get.assert_called_once_with(
path, 'directory') path, 'directory')
self._mock_isilon_api.delete_quota.assert_called_once_with(quota_id) self._mock_powerscale_api.delete_quota.assert_called_once_with(
quota_id)
mock_log.debug.assert_called_once_with(f'Removing quota {quota_id}') mock_log.debug.assert_called_once_with(f'Removing quota {quota_id}')
mock_log.error.assert_called_once_with( mock_log.error.assert_called_once_with(
_('Failed to delete quota "%(quota_id)s" for ' _('Failed to delete quota "%(quota_id)s" for '
@@ -382,35 +389,41 @@ class IsilonTest(test.TestCase):
{'quota_id': quota_id, 'dir': path}) {'quota_id': quota_id, 'dir': path})
mock_log.warning.assert_not_called() mock_log.warning.assert_not_called()
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.isilon.LOG') @mock.patch(
'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
)
def test_delete_quota_not_found(self, mock_log): def test_delete_quota_not_found(self, mock_log):
path = '/path/to/quota' path = '/path/to/quota'
self._mock_isilon_api.quota_get.return_value = None self._mock_powerscale_api.quota_get.return_value = None
self.storage_connection._delete_quota(path) self.storage_connection._delete_quota(path)
self._mock_isilon_api.quota_get.assert_called_once_with( self._mock_powerscale_api.quota_get.assert_called_once_with(
path, 'directory') path, 'directory')
self._mock_isilon_api.delete_quota.assert_not_called() self._mock_powerscale_api.delete_quota.assert_not_called()
mock_log.debug.assert_not_called() mock_log.debug.assert_not_called()
mock_log.warning.assert_called_once_with(f'Quota not found for {path}') mock_log.warning.assert_called_once_with(f'Quota not found for {path}')
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.isilon.LOG') @mock.patch(
'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
)
def test_delete_directory_success(self, mock_log): def test_delete_directory_success(self, mock_log):
path = '/path/to/directory' path = '/path/to/directory'
self._mock_isilon_api.is_path_existent.return_value = True self._mock_powerscale_api.is_path_existent.return_value = True
self._mock_isilon_api.delete_path.return_value = True self._mock_powerscale_api.delete_path.return_value = True
self.storage_connection._delete_directory(path) self.storage_connection._delete_directory(path)
self._mock_isilon_api.delete_path.assert_called_once_with( self._mock_powerscale_api.delete_path.assert_called_once_with(
path, recursive=True) path, recursive=True)
mock_log.debug.assert_called_once_with(f'Removing directory {path}') mock_log.debug.assert_called_once_with(f'Removing directory {path}')
mock_log.warning.assert_not_called() mock_log.warning.assert_not_called()
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.isilon.LOG') @mock.patch(
'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
)
def test_delete_directory_failure(self, mock_log): def test_delete_directory_failure(self, mock_log):
path = '/path/to/directory' path = '/path/to/directory'
self._mock_isilon_api.is_path_existent.return_value = True self._mock_powerscale_api.is_path_existent.return_value = True
self._mock_isilon_api.delete_path.return_value = False self._mock_powerscale_api.delete_path.return_value = False
self.storage_connection._delete_directory(path) self.storage_connection._delete_directory(path)
self._mock_isilon_api.delete_path.assert_called_once_with( self._mock_powerscale_api.delete_path.assert_called_once_with(
path, recursive=True) path, recursive=True)
mock_log.debug.assert_called_once_with(f'Removing directory {path}') mock_log.debug.assert_called_once_with(f'Removing directory {path}')
mock_log.error.assert_called_once_with( mock_log.error.assert_called_once_with(
@@ -418,12 +431,14 @@ class IsilonTest(test.TestCase):
{'dir': path}) {'dir': path})
mock_log.warning.assert_not_called() mock_log.warning.assert_not_called()
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.isilon.LOG') @mock.patch(
'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
)
def test_delete_directory_not_found(self, mock_log): def test_delete_directory_not_found(self, mock_log):
path = '/path/to/directory' path = '/path/to/directory'
self._mock_isilon_api.is_path_existent.return_value = False self._mock_powerscale_api.is_path_existent.return_value = False
self.storage_connection._delete_directory(path) self.storage_connection._delete_directory(path)
self._mock_isilon_api.delete_path.assert_not_called() self._mock_powerscale_api.delete_path.assert_not_called()
mock_log.warning.assert_called_once_with( mock_log.warning.assert_called_once_with(
_('Directory not found for %s') % path) _('Directory not found for %s') % path)
@@ -432,24 +447,24 @@ class IsilonTest(test.TestCase):
snapshot_name = "snapshot01" snapshot_name = "snapshot01"
snapshot_path = '/ifs/home/admin' snapshot_path = '/ifs/home/admin'
snapshot = {'name': snapshot_name, 'share_name': snapshot_path} snapshot = {'name': snapshot_name, 'share_name': snapshot_path}
self.assertFalse(self._mock_isilon_api.delete_snapshot.called) self.assertFalse(self._mock_powerscale_api.delete_snapshot.called)
# delete the created snapshot # delete the created snapshot
self.storage_connection.delete_snapshot(self.mock_context, snapshot, self.storage_connection.delete_snapshot(self.mock_context, snapshot,
None) None)
# verify the API call was made to delete the snapshot # verify the API call was made to delete the snapshot
self._mock_isilon_api.delete_snapshot.assert_called_once_with( self._mock_powerscale_api.delete_snapshot.assert_called_once_with(
snapshot_name) snapshot_name)
def test_delete_snapshot_failure(self): def test_delete_snapshot_failure(self):
snapshot = {'name': 'test_snapshot'} snapshot = {'name': 'test_snapshot'}
self._mock_isilon_api.delete_snapshot.return_value = False self._mock_powerscale_api.delete_snapshot.return_value = False
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
self.storage_connection.delete_snapshot, self.storage_connection.delete_snapshot,
self.mock_context, snapshot, None) self.mock_context, snapshot, None)
self._mock_isilon_api.delete_snapshot.assert_called_once_with( self._mock_powerscale_api.delete_snapshot.assert_called_once_with(
snapshot['name']) snapshot['name'])
def test_ensure_share(self): def test_ensure_share(self):
@@ -459,11 +474,10 @@ class IsilonTest(test.TestCase):
self.mock_context, share, None) self.mock_context, share, None)
@mock.patch( @mock.patch(
'manila.share.drivers.dell_emc.plugins.isilon.isilon.isilon_api.' 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.'
'IsilonApi', 'powerscale_api.PowerScaleApi', autospec=True)
autospec=True)
def test_connect(self, mock_isi_api): def test_connect(self, mock_isi_api):
storage_connection = isilon.IsilonStorageConnection(LOG) storage_connection = powerscale.PowerScaleStorageConnection(LOG)
# execute method under test # execute method under test
storage_connection.connect( storage_connection.connect(
@@ -488,18 +502,17 @@ class IsilonTest(test.TestCase):
storage_connection._dir_permission) storage_connection._dir_permission)
@mock.patch( @mock.patch(
'manila.share.drivers.dell_emc.plugins.isilon.isilon.isilon_api.' 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.'
'IsilonApi', 'powerscale_api.PowerScaleApi', autospec=True)
autospec=True)
def test_connect_root_dir_does_not_exist(self, mock_isi_api): def test_connect_root_dir_does_not_exist(self, mock_isi_api):
mock_isilon_api = mock_isi_api.return_value mock_powerscale_api = mock_isi_api.return_value
mock_isilon_api.is_path_existent.return_value = False mock_powerscale_api.is_path_existent.return_value = False
storage_connection = isilon.IsilonStorageConnection(LOG) storage_connection = powerscale.PowerScaleStorageConnection(LOG)
# call method under test # call method under test
storage_connection.connect(self.mock_emc_driver, self.mock_context) storage_connection.connect(self.mock_emc_driver, self.mock_context)
mock_isilon_api.create_directory.assert_called_once_with( mock_powerscale_api.create_directory.assert_called_once_with(
self.ROOT_DIR, recursive=True) self.ROOT_DIR, recursive=True)
def test_connect_invalid_config(self): def test_connect_invalid_config(self):
@@ -513,11 +526,11 @@ class IsilonTest(test.TestCase):
) )
def test_update_share_stats(self): def test_update_share_stats(self):
self._mock_isilon_api.get_space_stats.return_value = { self._mock_powerscale_api.get_space_stats.return_value = {
'total': 1000 * units.Gi, 'total': 1000 * units.Gi,
'free': 100 * units.Gi, 'free': 100 * units.Gi,
} }
self._mock_isilon_api.get_allocated_space.return_value = 2110.0 self._mock_powerscale_api.get_allocated_space.return_value = 2110.0
stats_dict = {'share_backend_name': 'PowerScale_backend'} stats_dict = {'share_backend_name': 'PowerScale_backend'}
self.storage_connection.update_share_stats(stats_dict) self.storage_connection.update_share_stats(stats_dict)
@@ -535,7 +548,7 @@ class IsilonTest(test.TestCase):
} }
expected_stats = { expected_stats = {
'share_backend_name': 'PowerScale_backend', 'share_backend_name': 'PowerScale_backend',
'driver_version': isilon.VERSION, 'driver_version': powerscale.VERSION,
'storage_protocol': 'NFS_CIFS', 'storage_protocol': 'NFS_CIFS',
'pools': [expected_pool_stats] 'pools': [expected_pool_stats]
} }
@@ -555,14 +568,14 @@ class IsilonTest(test.TestCase):
"share_proto": 'NFS', "share_proto": 'NFS',
"size": new_share_size "size": new_share_size
} }
self._mock_isilon_api.quota_get.return_value = {'id': quota_id} self._mock_powerscale_api.quota_get.return_value = {'id': quota_id}
self.assertFalse(self._mock_isilon_api.quota_set.called) self.assertFalse(self._mock_powerscale_api.quota_set.called)
self.storage_connection.extend_share(share, new_share_size) self.storage_connection.extend_share(share, new_share_size)
share_path = '{0}/{1}'.format(self.ROOT_DIR, self.SHARE_NAME) share_path = '{0}/{1}'.format(self.ROOT_DIR, self.SHARE_NAME)
expected_quota_size = new_share_size * units.Gi expected_quota_size = new_share_size * units.Gi
self._mock_isilon_api.quota_set.assert_called_once_with( self._mock_powerscale_api.quota_set.assert_called_once_with(
share_path, 'directory', expected_quota_size) share_path, 'directory', expected_quota_size)
def test_update_access_add_nfs(self): def test_update_access_add_nfs(self):
@@ -571,8 +584,9 @@ class IsilonTest(test.TestCase):
"share_proto": 'NFS', "share_proto": 'NFS',
} }
fake_export_id = 4 fake_export_id = 4
self._mock_isilon_api.lookup_nfs_export.return_value = fake_export_id self._mock_powerscale_api.lookup_nfs_export.return_value = (
self._mock_isilon_api.get_nfs_export.return_value = { fake_export_id)
self._mock_powerscale_api.get_nfs_export.return_value = {
'clients': [], 'clients': [],
'read_only_clients': [] 'read_only_clients': []
} }
@@ -583,7 +597,7 @@ class IsilonTest(test.TestCase):
'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08' 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
} }
access_rules = [nfs_access] access_rules = [nfs_access]
self._mock_isilon_api.modify_nfs_export_access.return_value = True self._mock_powerscale_api.modify_nfs_export_access.return_value = True
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], self.mock_context, share, access_rules, [],
[], share_server=None) [], share_server=None)
@@ -592,8 +606,8 @@ class IsilonTest(test.TestCase):
'state': 'active' 'state': 'active'
} }
} }
self._mock_isilon_api.modify_nfs_export_access.assert_called_once_with( self._mock_powerscale_api.modify_nfs_export_access. \
fake_export_id, [], ['10.1.1.10']) assert_called_once_with(fake_export_id, [], ['10.1.1.10'])
self.assertEqual(expected_rule_map, rule_map) self.assertEqual(expected_rule_map, rule_map)
def test_update_access_add_cifs(self): def test_update_access_add_cifs(self):
@@ -609,7 +623,7 @@ class IsilonTest(test.TestCase):
} }
access_rules = [access] access_rules = [access]
self._mock_isilon_api.get_user_sid.return_value = { self._mock_powerscale_api.get_user_sid.return_value = {
'id': 'SID:S-1-5-22', 'id': 'SID:S-1-5-22',
'name': 'foo', 'name': 'foo',
'type': 'user', 'type': 'user',
@@ -628,8 +642,9 @@ class IsilonTest(test.TestCase):
} }
} }
] ]
self._mock_isilon_api.modify_smb_share_access.assert_called_once_with( self._mock_powerscale_api.modify_smb_share_access.\
self.SHARE_NAME, host_acl=[], permissions=expected_permissions) assert_called_once_with(
self.SHARE_NAME, host_acl=[], permissions=expected_permissions)
expected_rule_map = { expected_rule_map = {
'09960614-8574-4e03-89cf-7cf267b0bd08': { '09960614-8574-4e03-89cf-7cf267b0bd08': {
'state': 'active' 'state': 'active'
@@ -643,20 +658,21 @@ class IsilonTest(test.TestCase):
"share_proto": 'NFS', "share_proto": 'NFS',
} }
fake_export_id = 4 fake_export_id = 4
self._mock_isilon_api.lookup_nfs_export.return_value = fake_export_id self._mock_powerscale_api.lookup_nfs_export.return_value = (
fake_export_id)
# simulate an IP added to the whitelist # simulate an IP added to the whitelist
ip_addr = '10.0.0.4' ip_addr = '10.0.0.4'
ip_addr_ro = '10.0.0.50' ip_addr_ro = '10.0.0.50'
self._mock_isilon_api.get_nfs_export.return_value = { self._mock_powerscale_api.get_nfs_export.return_value = {
'clients': [ip_addr], 'read_only_clients': [ip_addr_ro]} 'clients': [ip_addr], 'read_only_clients': [ip_addr_ro]}
access_rules = [] access_rules = []
self._mock_isilon_api.modify_nfs_export_access.return_value = True self._mock_powerscale_api.modify_nfs_export_access.return_value = True
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], []) self.mock_context, share, access_rules, [], [])
self._mock_isilon_api.modify_nfs_export_access.assert_called_once_with( self._mock_powerscale_api.modify_nfs_export_access. \
fake_export_id, [], []) assert_called_once_with(fake_export_id, [], [])
self.assertEqual({}, rule_map) self.assertEqual({}, rule_map)
def test_update_access_delete_cifs(self): def test_update_access_delete_cifs(self):
@@ -665,7 +681,7 @@ class IsilonTest(test.TestCase):
"share_proto": 'CIFS', "share_proto": 'CIFS',
} }
access_rules = [] access_rules = []
self._mock_isilon_api.lookup_smb_share.return_value = { self._mock_powerscale_api.lookup_smb_share.return_value = {
'permissions': [ 'permissions': [
{ {
'permission': 'change', 'permission': 'change',
@@ -680,12 +696,13 @@ class IsilonTest(test.TestCase):
] ]
} }
self._mock_isilon_api.modify_smb_share_access.return_value = None self._mock_powerscale_api.modify_smb_share_access.return_value = None
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], []) self.mock_context, share, access_rules, [], [])
self._mock_isilon_api.modify_smb_share_access.assert_called_once_with( self._mock_powerscale_api.modify_smb_share_access.\
self.SHARE_NAME, host_acl=[], permissions=[]) assert_called_once_with(
self.SHARE_NAME, host_acl=[], permissions=[])
self.assertEqual({}, rule_map) self.assertEqual({}, rule_map)
def test_update_access_nfs_share_not_found(self): def test_update_access_nfs_share_not_found(self):
@@ -700,7 +717,7 @@ class IsilonTest(test.TestCase):
'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08' 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
} }
access_rules = [access] access_rules = [access]
self._mock_isilon_api.lookup_nfs_export.return_value = None self._mock_powerscale_api.lookup_nfs_export.return_value = None
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], []) self.mock_context, share, access_rules, [], [])
@@ -724,7 +741,7 @@ class IsilonTest(test.TestCase):
'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08' 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
} }
access_rules = [access] access_rules = [access]
self._mock_isilon_api.modify_nfs_export_access.return_value = False self._mock_powerscale_api.modify_nfs_export_access.return_value = False
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], []) self.mock_context, share, access_rules, [], [])
@@ -748,7 +765,7 @@ class IsilonTest(test.TestCase):
'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08' 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
} }
access_rules = [access] access_rules = [access]
self._mock_isilon_api.modify_smb_share_access.return_value = False self._mock_powerscale_api.modify_smb_share_access.return_value = False
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, None, None) self.mock_context, share, access_rules, None, None)
@@ -772,7 +789,7 @@ class IsilonTest(test.TestCase):
'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08' 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
} }
access_rules = [access] access_rules = [access]
self._mock_isilon_api.modify_smb_share_access.return_value = True self._mock_powerscale_api.modify_smb_share_access.return_value = True
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], []) self.mock_context, share, access_rules, [], [])
@@ -796,8 +813,8 @@ class IsilonTest(test.TestCase):
'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08' 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
} }
access_rules = [access] access_rules = [access]
self._mock_isilon_api.get_user_sid.return_value = None self._mock_powerscale_api.get_user_sid.return_value = None
self._mock_isilon_api.modify_smb_share_access.return_value = True self._mock_powerscale_api.modify_smb_share_access.return_value = True
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], []) self.mock_context, share, access_rules, [], [])
@@ -839,8 +856,9 @@ class IsilonTest(test.TestCase):
"share_proto": 'NFS', "share_proto": 'NFS',
} }
fake_export_id = 4 fake_export_id = 4
self._mock_isilon_api.lookup_nfs_export.return_value = fake_export_id self._mock_powerscale_api.lookup_nfs_export.return_value = (
self._mock_isilon_api.get_nfs_export.return_value = { fake_export_id)
self._mock_powerscale_api.get_nfs_export.return_value = {
'clients': ['10.1.1.8'], 'clients': ['10.1.1.8'],
'read_only_clients': ['10.2.0.2'] 'read_only_clients': ['10.2.0.2']
} }
@@ -858,7 +876,7 @@ class IsilonTest(test.TestCase):
} }
access_rules = [nfs_access_1, nfs_access_2] access_rules = [nfs_access_1, nfs_access_2]
self._mock_isilon_api.modify_nfs_export_access.return_value = True self._mock_powerscale_api.modify_nfs_export_access.return_value = True
rule_map = self.storage_connection.update_access( rule_map = self.storage_connection.update_access(
self.mock_context, share, access_rules, [], []) self.mock_context, share, access_rules, [], [])
@@ -871,8 +889,10 @@ class IsilonTest(test.TestCase):
'state': 'active' 'state': 'active'
} }
} }
self._mock_isilon_api.modify_nfs_export_access.assert_called_once_with( self._mock_powerscale_api.modify_nfs_export_access. \
fake_export_id, ['10.1.1.2'], ['10.1.1.10']) assert_called_once_with(fake_export_id,
['10.1.1.2'],
['10.1.1.10'])
self.assertEqual(expected_rule_map, rule_map) self.assertEqual(expected_rule_map, rule_map)
def test_update_access_recover_cifs(self): def test_update_access_recover_cifs(self):
@@ -880,12 +900,12 @@ class IsilonTest(test.TestCase):
"name": self.SHARE_NAME, "name": self.SHARE_NAME,
"share_proto": 'CIFS', "share_proto": 'CIFS',
} }
self._mock_isilon_api.get_user_sid.return_value = { self._mock_powerscale_api.get_user_sid.return_value = {
'id': 'SID:S-1-5-22', 'id': 'SID:S-1-5-22',
'name': 'testuser', 'name': 'testuser',
'type': 'user', 'type': 'user',
} }
self._mock_isilon_api.modify_smb_share_access.return_value = True self._mock_powerscale_api.modify_smb_share_access.return_value = True
access_1 = { access_1 = {
'access_type': 'ip', 'access_type': 'ip',
'access_to': '10.1.1.10', 'access_to': '10.1.1.10',
@@ -925,13 +945,15 @@ class IsilonTest(test.TestCase):
'state': 'active' 'state': 'active'
} }
} }
self._mock_isilon_api.lookup_smb_share.assert_not_called() self._mock_powerscale_api.lookup_smb_share.assert_not_called()
self._mock_isilon_api.get_user_sid.assert_called_once_with('testuser') self._mock_powerscale_api.get_user_sid.assert_called_once_with(
self._mock_isilon_api.modify_smb_share_access.assert_called_once_with( 'testuser')
self.SHARE_NAME, self._mock_powerscale_api.modify_smb_share_access.\
host_acl=expected_data['host_acl'], assert_called_once_with(
permissions=expected_data['permissions'] self.SHARE_NAME,
) host_acl=expected_data['host_acl'],
permissions=expected_data['permissions']
)
self.assertEqual(expected_rule_map, rule_map) self.assertEqual(expected_rule_map, rule_map)
def test_update_access_with_cifs_ip_readonly(self): def test_update_access_with_cifs_ip_readonly(self):
@@ -951,46 +973,47 @@ class IsilonTest(test.TestCase):
path = '/path/to/quota' path = '/path/to/quota'
quota_id = '123' quota_id = '123'
quota_data = {'id': quota_id} quota_data = {'id': quota_id}
self._mock_isilon_api.quota_get.return_value = quota_data self._mock_powerscale_api.quota_get.return_value = quota_data
self._mock_isilon_api.delete_quota.return_value = True self._mock_powerscale_api.delete_quota.return_value = True
self.storage_connection._delete_quota(path) self.storage_connection._delete_quota(path)
self._mock_isilon_api.quota_get.assert_called_once_with( self._mock_powerscale_api.quota_get.assert_called_once_with(
path, 'directory') path, 'directory')
self._mock_isilon_api.delete_quota.assert_called_once_with(quota_id) self._mock_powerscale_api.delete_quota.assert_called_once_with(
quota_id)
def test_delete_quota_when_quota_does_not_exist(self): def test_delete_quota_when_quota_does_not_exist(self):
path = '/path/to/quota' path = '/path/to/quota'
self._mock_isilon_api.quota_get.return_value = None self._mock_powerscale_api.quota_get.return_value = None
self.storage_connection._delete_quota(path) self.storage_connection._delete_quota(path)
self._mock_isilon_api.quota_get.assert_called_once_with( self._mock_powerscale_api.quota_get.assert_called_once_with(
path, 'directory') path, 'directory')
self._mock_isilon_api.delete_quota.assert_not_called() self._mock_powerscale_api.delete_quota.assert_not_called()
def test_delete_directory_when_path_exists(self): def test_delete_directory_when_path_exists(self):
path = '/path/to/directory' path = '/path/to/directory'
self.storage_connection._delete_directory(path) self.storage_connection._delete_directory(path)
self._mock_isilon_api.is_path_existent.assert_called_with(path) self._mock_powerscale_api.is_path_existent.assert_called_with(path)
self._mock_isilon_api.delete_path.assert_called_with( self._mock_powerscale_api.delete_path.assert_called_with(
path, recursive=True) path, recursive=True)
def test_delete_directory_when_path_does_not_exist(self): def test_delete_directory_when_path_does_not_exist(self):
path = '/path/to/directory' path = '/path/to/directory'
self._mock_isilon_api.is_path_existent.return_value = False self._mock_powerscale_api.is_path_existent.return_value = False
self.storage_connection._delete_directory(path) self.storage_connection._delete_directory(path)
self._mock_isilon_api.is_path_existent.assert_called_with(path) self._mock_powerscale_api.is_path_existent.assert_called_with(path)
self._mock_isilon_api.delete_path.assert_not_called() self._mock_powerscale_api.delete_path.assert_not_called()
def test_get_backend_info(self): def test_get_backend_info(self):
self._mock_isilon_api.get_cluster_version.return_value = '1.0' self._mock_powerscale_api.get_cluster_version.return_value = '1.0'
result = self.storage_connection.get_backend_info(None) result = self.storage_connection.get_backend_info(None)
expected_info = { expected_info = {
'driver_version': isilon.VERSION, 'driver_version': powerscale.VERSION,
'cluster_version': '1.0', 'cluster_version': '1.0',
'rest_server': self.ISILON_ADDR, 'rest_server': self.POWERSCALE_ADDR,
'rest_port': '8080', 'rest_port': '8080',
} }
self.assertEqual(expected_info, result) self.assertEqual(expected_info, result)
@@ -1005,7 +1028,7 @@ class IsilonTest(test.TestCase):
location = '10.0.0.1:/ifs/my_share' location = '10.0.0.1:/ifs/my_share'
self.storage_connection._get_container_path = mock.MagicMock( self.storage_connection._get_container_path = mock.MagicMock(
return_value=container_path) return_value=container_path)
self._mock_isilon_api.lookup_nfs_export.return_value = '123' self._mock_powerscale_api.lookup_nfs_export.return_value = '123'
result = self.storage_connection.ensure_shares(None, [share]) result = self.storage_connection.ensure_shares(None, [share])
expected_result = { expected_result = {
@@ -1024,7 +1047,7 @@ class IsilonTest(test.TestCase):
'name': 'my_share', 'name': 'my_share',
} }
location = '\\\\10.0.0.1\\my_share' location = '\\\\10.0.0.1\\my_share'
self._mock_isilon_api.lookup_smb_share.return_value = share self._mock_powerscale_api.lookup_smb_share.return_value = share
result = self.storage_connection.ensure_shares(None, [share]) result = self.storage_connection.ensure_shares(None, [share])
expected_result = { expected_result = {
@@ -1042,7 +1065,7 @@ class IsilonTest(test.TestCase):
'share_proto': 'NFS', 'share_proto': 'NFS',
'name': 'my_share', 'name': 'my_share',
} }
self._mock_isilon_api.lookup_nfs_export.return_value = None self._mock_powerscale_api.lookup_nfs_export.return_value = None
result = self.storage_connection.ensure_shares(None, [share]) result = self.storage_connection.ensure_shares(None, [share])
expected_result = { expected_result = {
'123': { '123': {
@@ -1059,7 +1082,7 @@ class IsilonTest(test.TestCase):
'share_proto': 'CIFS', 'share_proto': 'CIFS',
'name': 'my_share', 'name': 'my_share',
} }
self._mock_isilon_api.lookup_smb_share.return_value = None self._mock_powerscale_api.lookup_smb_share.return_value = None
result = self.storage_connection.ensure_shares(None, [share]) result = self.storage_connection.ensure_shares(None, [share])
expected_result = { expected_result = {
'123': { '123': {

View File

@@ -21,40 +21,40 @@ import requests
import requests_mock import requests_mock
from manila import exception from manila import exception
from manila.share.drivers.dell_emc.plugins.isilon import isilon_api from manila.share.drivers.dell_emc.plugins.powerscale import powerscale_api
from manila import test from manila import test
@ddt.ddt @ddt.ddt
class IsilonApiTest(test.TestCase): class PowerScaleApiTest(test.TestCase):
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.' @mock.patch('manila.share.drivers.dell_emc.plugins.powerscale.'
'isilon_api.IsilonApi.create_session') 'powerscale_api.PowerScaleApi.create_session')
def setUp(self, mockup_create_session): def setUp(self, mockup_create_session):
super(IsilonApiTest, self).setUp() super(PowerScaleApiTest, self).setUp()
mockup_create_session.return_value = True mockup_create_session.return_value = True
self._mock_url = 'https://localhost:8080' self._mock_url = 'https://localhost:8080'
self.username = 'admin' self.username = 'admin'
self.password = 'pwd' self.password = 'pwd'
self.dir_permission = '0777' self.dir_permission = '0777'
self.isilon_api = isilon_api.IsilonApi( self.powerscale_api = powerscale_api.PowerScaleApi(
self._mock_url, self.username, self.password, self._mock_url, self.username, self.password,
dir_permission=self.dir_permission dir_permission=self.dir_permission
) )
self.isilon_api_threshold = isilon_api.IsilonApi( self.powerscale_api_threshold = powerscale_api.PowerScaleApi(
self._mock_url, self.username, self.password, self._mock_url, self.username, self.password,
dir_permission=self.dir_permission, dir_permission=self.dir_permission,
threshold_limit=80 threshold_limit=80
) )
@mock.patch('manila.share.drivers.dell_emc.plugins.isilon.' @mock.patch('manila.share.drivers.dell_emc.plugins.powerscale.'
'isilon_api.IsilonApi.create_session') 'powerscale_api.PowerScaleApi.create_session')
def test__init__login_failure(self, mockup_create_session): def test__init__login_failure(self, mockup_create_session):
mockup_create_session.return_value = False mockup_create_session.return_value = False
self.assertRaises( self.assertRaises(
exception.BadConfigurationException, exception.BadConfigurationException,
self.isilon_api.__init__, self.powerscale_api.__init__,
self._mock_url, self._mock_url,
self.username, self.username,
self.password, self.password,
@@ -64,14 +64,14 @@ class IsilonApiTest(test.TestCase):
) )
def test__verify_cert(self): def test__verify_cert(self):
verify_cert = self.isilon_api.verify_ssl_cert verify_cert = self.powerscale_api.verify_ssl_cert
certificate_path = self.isilon_api.certificate_path certificate_path = self.powerscale_api.certificate_path
self.isilon_api.verify_ssl_cert = True self.powerscale_api.verify_ssl_cert = True
self.isilon_api.certificate_path = "fake_certificate_path" self.powerscale_api.certificate_path = "fake_certificate_path"
self.assertEqual(self.isilon_api._verify_cert, self.assertEqual(self.powerscale_api._verify_cert,
self.isilon_api.certificate_path) self.powerscale_api.certificate_path)
self.isilon_api.verify_ssl_cert = verify_cert self.powerscale_api.verify_ssl_cert = verify_cert
self.isilon_api.certificate_path = certificate_path self.powerscale_api.certificate_path = certificate_path
@mock.patch('requests.Session.request') @mock.patch('requests.Session.request')
def test_create_session_success(self, mock_request): def test_create_session_success(self, mock_request):
@@ -80,7 +80,8 @@ class IsilonApiTest(test.TestCase):
mock_response.cookies = {'isisessid': 'test_session_token', mock_response.cookies = {'isisessid': 'test_session_token',
'isicsrf': 'test_csrf_token'} 'isicsrf': 'test_csrf_token'}
mock_request.return_value = mock_response mock_request.return_value = mock_response
result = self.isilon_api.create_session(self.username, self.password) result = self.powerscale_api.create_session(
self.username, self.password)
mock_request.assert_called_once_with( mock_request.assert_called_once_with(
'POST', self._mock_url + '/session/1/session', 'POST', self._mock_url + '/session/1/session',
headers={"Content-type": "application/json"}, headers={"Content-type": "application/json"},
@@ -90,8 +91,9 @@ class IsilonApiTest(test.TestCase):
verify=False verify=False
) )
self.assertTrue(result) self.assertTrue(result)
self.assertEqual(self.isilon_api.session_token, 'test_session_token') self.assertEqual(self.powerscale_api.session_token,
self.assertEqual(self.isilon_api.csrf_token, 'test_csrf_token') 'test_session_token')
self.assertEqual(self.powerscale_api.csrf_token, 'test_csrf_token')
@mock.patch('requests.Session.request') @mock.patch('requests.Session.request')
def test_create_session_failure(self, mock_request): def test_create_session_failure(self, mock_request):
@@ -100,10 +102,11 @@ class IsilonApiTest(test.TestCase):
mock_response.json.return_value = { mock_response.json.return_value = {
'message': 'Username or password is incorrect.'} 'message': 'Username or password is incorrect.'}
mock_request.return_value = mock_response mock_request.return_value = mock_response
result = self.isilon_api.create_session(self.username, self.password) result = self.powerscale_api.create_session(
self.username, self.password)
self.assertFalse(result) self.assertFalse(result)
self.assertIsNone(self.isilon_api.session_token) self.assertIsNone(self.powerscale_api.session_token)
self.assertIsNone(self.isilon_api.csrf_token) self.assertIsNone(self.powerscale_api.csrf_token)
@ddt.data(False, True) @ddt.data(False, True)
def test_create_directory(self, is_recursive): def test_create_directory(self, is_recursive):
@@ -112,8 +115,8 @@ class IsilonApiTest(test.TestCase):
self.assertEqual(0, len(m.request_history)) self.assertEqual(0, len(m.request_history))
self._add_create_directory_response(m, path, is_recursive) self._add_create_directory_response(m, path, is_recursive)
r = self.isilon_api.create_directory(path, r = self.powerscale_api.create_directory(path,
recursive=is_recursive) recursive=is_recursive)
self.assertTrue(r) self.assertTrue(r)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
@@ -123,14 +126,14 @@ class IsilonApiTest(test.TestCase):
def test_create_directory_no_permission(self): def test_create_directory_no_permission(self):
with requests_mock.Mocker() as m: with requests_mock.Mocker() as m:
path = '/ifs/test' path = '/ifs/test'
self.isilon_api.dir_permission = None self.powerscale_api.dir_permission = None
self.assertEqual(0, len(m.request_history)) self.assertEqual(0, len(m.request_history))
self._add_create_directory_response(m, path, True) self._add_create_directory_response(m, path, True)
r = self.isilon_api.create_directory(path, r = self.powerscale_api.create_directory(path,
recursive=True) recursive=True)
self.isilon_api.dir_permission = '0777' self.powerscale_api.dir_permission = '0777'
self.assertTrue(r) self.assertTrue(r)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
request = m.request_history[0] request = m.request_history[0]
@@ -195,7 +198,7 @@ class IsilonApiTest(test.TestCase):
snapshot_name) snapshot_name)
# Call method under test # Call method under test
self.isilon_api.clone_snapshot(snapshot_name, fq_target_dir) self.powerscale_api.clone_snapshot(snapshot_name, fq_target_dir)
# Verify calls needed to clone the source snapshot to the target dir # Verify calls needed to clone the source snapshot to the target dir
expected_calls = [] expected_calls = []
@@ -203,8 +206,8 @@ class IsilonApiTest(test.TestCase):
'file1', 'file2', 'dir1/file11', 'dir1/file12', 'file1', 'file2', 'dir1/file11', 'dir1/file12',
'dir2/file21', 'dir2/file22'] 'dir2/file21', 'dir2/file22']
for path in clone_path_list: for path in clone_path_list:
expected_call = IsilonApiTest.ExpectedCall( expected_call = PowerScaleApiTest.ExpectedCall(
IsilonApiTest.ExpectedCall.FILE_CLONE, PowerScaleApiTest.ExpectedCall.FILE_CLONE,
self._mock_url + '/namespace/ifs/admin/target/' + path, self._mock_url + '/namespace/ifs/admin/target/' + path,
['/ifs/admin/target/' + path, '/ifs/admin/source/' + path, ['/ifs/admin/target/' + path, '/ifs/admin/source/' + path,
snapshot_name]) snapshot_name])
@@ -214,8 +217,8 @@ class IsilonApiTest(test.TestCase):
('/dir2?recursive', '/dir2'), ('/dir2?recursive', '/dir2'),
('?recursive=', '')] ('?recursive=', '')]
for url, path in dir_path_list: for url, path in dir_path_list:
expected_call = IsilonApiTest.ExpectedCall( expected_call = PowerScaleApiTest.ExpectedCall(
IsilonApiTest.ExpectedCall.DIR_CREATION, PowerScaleApiTest.ExpectedCall.DIR_CREATION,
self._mock_url + '/namespace/ifs/admin/target' + url, self._mock_url + '/namespace/ifs/admin/target' + url,
['/ifs/admin/target' + path, False]) ['/ifs/admin/target' + path, False])
expected_calls.append(expected_call) expected_calls.append(expected_call)
@@ -258,7 +261,7 @@ class IsilonApiTest(test.TestCase):
json_str = '{"my_json": "test123"}' json_str = '{"my_json": "test123"}'
self._add_get_directory_listing_response(m, fq_dir_path, json_str) self._add_get_directory_listing_response(m, fq_dir_path, json_str)
actual_json = self.isilon_api.get_directory_listing(fq_dir_path) actual_json = self.powerscale_api.get_directory_listing(fq_dir_path)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(json.loads(json_str), actual_json) self.assertEqual(json.loads(json_str), actual_json)
@@ -272,7 +275,7 @@ class IsilonApiTest(test.TestCase):
m.head('{0}/namespace{1}'.format(self._mock_url, path), m.head('{0}/namespace{1}'.format(self._mock_url, path),
status_code=status_code) status_code=status_code)
r = self.isilon_api.is_path_existent(path) r = self.powerscale_api.is_path_existent(path)
self.assertEqual(expected_return_value, r) self.assertEqual(expected_return_value, r)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
@@ -284,7 +287,8 @@ class IsilonApiTest(test.TestCase):
status_code=400) status_code=400)
self.assertRaises( self.assertRaises(
requests.exceptions.HTTPError, self.isilon_api.is_path_existent, requests.exceptions.HTTPError,
self.powerscale_api.is_path_existent,
'/ifs/home/admin') '/ifs/home/admin')
@ddt.data( @ddt.data(
@@ -300,7 +304,7 @@ class IsilonApiTest(test.TestCase):
self._add_get_snapshot_response(m, snapshot_name, json_body, self._add_get_snapshot_response(m, snapshot_name, json_body,
status=status_code) status=status_code)
r = self.isilon_api.get_snapshot(snapshot_name) r = self.powerscale_api.get_snapshot(snapshot_name)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(expected_return_value, r) self.assertEqual(expected_return_value, r)
@@ -313,7 +317,7 @@ class IsilonApiTest(test.TestCase):
m, snapshot_name, json_body, status=400) m, snapshot_name, json_body, status=400)
self.assertRaises( self.assertRaises(
requests.exceptions.HTTPError, self.isilon_api.get_snapshot, requests.exceptions.HTTPError, self.powerscale_api.get_snapshot,
snapshot_name) snapshot_name)
@requests_mock.mock() @requests_mock.mock()
@@ -323,7 +327,7 @@ class IsilonApiTest(test.TestCase):
m.get('{0}/platform/1/snapshot/snapshots'.format(self._mock_url), m.get('{0}/platform/1/snapshot/snapshots'.format(self._mock_url),
status_code=200, json=json.loads(snapshot_json)) status_code=200, json=json.loads(snapshot_json))
r = self.isilon_api.get_snapshots() r = self.powerscale_api.get_snapshots()
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(json.loads(snapshot_json), r) self.assertEqual(json.loads(snapshot_json), r)
@@ -335,7 +339,7 @@ class IsilonApiTest(test.TestCase):
status_code=404) status_code=404)
self.assertRaises(requests.exceptions.HTTPError, self.assertRaises(requests.exceptions.HTTPError,
self.isilon_api.get_snapshots) self.powerscale_api.get_snapshots)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
@@ -355,7 +359,7 @@ class IsilonApiTest(test.TestCase):
share_path.replace('/', '%2F')), share_path.replace('/', '%2F')),
json=json.loads(response_json)) json=json.loads(response_json))
r = self.isilon_api.lookup_nfs_export(share_path) r = self.powerscale_api.lookup_nfs_export(share_path)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(expected_return, r) self.assertEqual(expected_return, r)
@@ -370,7 +374,7 @@ class IsilonApiTest(test.TestCase):
.format(self._mock_url, export_id), .format(self._mock_url, export_id),
json=json.loads(response_json), status_code=status_code) json=json.loads(response_json), status_code=status_code)
r = self.isilon_api.get_nfs_export(export_id) r = self.powerscale_api.get_nfs_export(export_id)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(json.loads('{"id": 1}'), r) self.assertEqual(json.loads('{"id": 1}'), r)
@@ -385,7 +389,7 @@ class IsilonApiTest(test.TestCase):
.format(self._mock_url, export_id), .format(self._mock_url, export_id),
json=json.loads(response_json), status_code=status_code) json=json.loads(response_json), status_code=status_code)
r = self.isilon_api.get_nfs_export(export_id) r = self.powerscale_api.get_nfs_export(export_id)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertIsNone(r) self.assertIsNone(r)
@@ -400,7 +404,7 @@ class IsilonApiTest(test.TestCase):
.format(self._mock_url, share_name), status_code=200, .format(self._mock_url, share_name), status_code=200,
json=json.loads(response_json)) json=json.loads(response_json))
r = self.isilon_api.lookup_smb_share(share_name) r = self.powerscale_api.lookup_smb_share(share_name)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(json.loads(share_json), r) self.assertEqual(json.loads(share_json), r)
@@ -412,7 +416,7 @@ class IsilonApiTest(test.TestCase):
m.get('{0}/platform/1/protocols/smb/shares/{1}'.format( m.get('{0}/platform/1/protocols/smb/shares/{1}'.format(
self._mock_url, share_name), status_code=404) self._mock_url, share_name), status_code=404)
r = self.isilon_api.lookup_smb_share(share_name) r = self.powerscale_api.lookup_smb_share(share_name)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertIsNone(r) self.assertIsNone(r)
@@ -426,7 +430,7 @@ class IsilonApiTest(test.TestCase):
m.post(self._mock_url + '/platform/1/protocols/nfs/exports', m.post(self._mock_url + '/platform/1/protocols/nfs/exports',
status_code=status_code) status_code=status_code)
r = self.isilon_api.create_nfs_export(export_path) r = self.powerscale_api.create_nfs_export(export_path)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
call = m.request_history[0] call = m.request_history[0]
@@ -445,7 +449,7 @@ class IsilonApiTest(test.TestCase):
m.post(self._mock_url + '/platform/1/protocols/smb/shares', m.post(self._mock_url + '/platform/1/protocols/smb/shares',
status_code=status_code) status_code=status_code)
r = self.isilon_api.create_smb_share(share_name, share_path) r = self.powerscale_api.create_smb_share(share_name, share_path)
self.assertEqual(expected_return_value, r) self.assertEqual(expected_return_value, r)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
@@ -465,7 +469,7 @@ class IsilonApiTest(test.TestCase):
m.post(self._mock_url + '/platform/1/snapshot/snapshots', m.post(self._mock_url + '/platform/1/snapshot/snapshots',
status_code=201) status_code=201)
r = self.isilon_api.create_snapshot(snapshot_name, snapshot_path) r = self.powerscale_api.create_snapshot(snapshot_name, snapshot_path)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertTrue(r) self.assertTrue(r)
@@ -485,7 +489,7 @@ class IsilonApiTest(test.TestCase):
status_code=404) status_code=404)
self.assertEqual( self.assertEqual(
self.isilon_api.create_snapshot(snapshot_name, snapshot_path), self.powerscale_api.create_snapshot(snapshot_name, snapshot_path),
False False
) )
@@ -497,7 +501,8 @@ class IsilonApiTest(test.TestCase):
m.delete(self._mock_url + '/namespace' + fq_path + '?recursive=' m.delete(self._mock_url + '/namespace' + fq_path + '?recursive='
+ str(is_recursive_delete), status_code=204) + str(is_recursive_delete), status_code=204)
self.isilon_api.delete_path(fq_path, recursive=is_recursive_delete) self.powerscale_api.delete_path(
fq_path, recursive=is_recursive_delete)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
@@ -507,8 +512,9 @@ class IsilonApiTest(test.TestCase):
m.delete(self._mock_url + '/namespace' + fq_path + '?recursive=False', m.delete(self._mock_url + '/namespace' + fq_path + '?recursive=False',
status_code=403) status_code=403)
self.assertEqual(self.isilon_api.delete_path(fq_path, recursive=False), self.assertEqual(
False) self.powerscale_api.delete_path(
fq_path, recursive=False), False)
@ddt.data((204, True), (404, False)) @ddt.data((204, True), (404, False))
def test_delete_nfs_share(self, data): def test_delete_nfs_share(self, data):
@@ -520,7 +526,7 @@ class IsilonApiTest(test.TestCase):
.format(self._mock_url, share_number), .format(self._mock_url, share_number),
status_code=status_code) status_code=status_code)
r = self.isilon_api.delete_nfs_share(share_number) r = self.powerscale_api.delete_nfs_share(share_number)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(expected_return_value, r) self.assertEqual(expected_return_value, r)
@@ -536,7 +542,7 @@ class IsilonApiTest(test.TestCase):
.format(self._mock_url, share_name), .format(self._mock_url, share_name),
status_code=status_code) status_code=status_code)
r = self.isilon_api.delete_smb_share(share_name) r = self.powerscale_api.delete_smb_share(share_name)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
self.assertEqual(expected_return_value, r) self.assertEqual(expected_return_value, r)
@@ -547,7 +553,7 @@ class IsilonApiTest(test.TestCase):
m.delete(self._mock_url + '/platform/1/snapshot/snapshots/my_snapshot', m.delete(self._mock_url + '/platform/1/snapshot/snapshots/my_snapshot',
status_code=204) status_code=204)
self.isilon_api.delete_snapshot("my_snapshot") self.powerscale_api.delete_snapshot("my_snapshot")
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
@@ -557,7 +563,7 @@ class IsilonApiTest(test.TestCase):
status_code=403) status_code=403)
self.assertEqual( self.assertEqual(
self.isilon_api.delete_snapshot("my_snapshot"), False) self.powerscale_api.delete_snapshot("my_snapshot"), False)
@requests_mock.mock() @requests_mock.mock()
def test_quota_create(self, m): def test_quota_create(self, m):
@@ -566,7 +572,7 @@ class IsilonApiTest(test.TestCase):
self.assertEqual(0, len(m.request_history)) self.assertEqual(0, len(m.request_history))
m.post(self._mock_url + '/platform/1/quota/quotas', status_code=201) m.post(self._mock_url + '/platform/1/quota/quotas', status_code=201)
self.isilon_api.quota_create(quota_path, 'directory', quota_size) self.powerscale_api.quota_create(quota_path, 'directory', quota_size)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
expected_request_json = { expected_request_json = {
@@ -586,11 +592,14 @@ class IsilonApiTest(test.TestCase):
quota_size = 100 quota_size = 100
self.assertEqual(0, len(m.request_history)) self.assertEqual(0, len(m.request_history))
m.post(self._mock_url + '/platform/1/quota/quotas', status_code=201) m.post(self._mock_url + '/platform/1/quota/quotas', status_code=201)
self.isilon_api_threshold.quota_create(quota_path, self.powerscale_api_threshold.quota_create(
'directory', quota_path,
quota_size) 'directory',
quota_size
)
advisory_size = round( advisory_size = round(
(quota_size * self.isilon_api_threshold.threshold_limit) / 100) (quota_size * self.powerscale_api_threshold.threshold_limit) / 100)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
expected_request_json = { expected_request_json = {
'path': quota_path, 'path': quota_path,
@@ -612,7 +621,7 @@ class IsilonApiTest(test.TestCase):
self.assertRaises( self.assertRaises(
requests.exceptions.HTTPError, requests.exceptions.HTTPError,
self.isilon_api.quota_create, self.powerscale_api.quota_create,
quota_path, 'directory', 2 quota_path, 'directory', 2
) )
@@ -625,7 +634,7 @@ class IsilonApiTest(test.TestCase):
quota_path = "/ifs/manila/test" quota_path = "/ifs/manila/test"
quota_type = "directory" quota_type = "directory"
self.isilon_api.quota_get(quota_path, quota_type) self.powerscale_api.quota_get(quota_path, quota_type)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
request_query_string = m.request_history[0].qs request_query_string = m.request_history[0].qs
@@ -637,7 +646,7 @@ class IsilonApiTest(test.TestCase):
self.assertEqual(0, len(m.request_history)) self.assertEqual(0, len(m.request_history))
m.get(self._mock_url + '/platform/1/quota/quotas', status_code=404) m.get(self._mock_url + '/platform/1/quota/quotas', status_code=404)
response = self.isilon_api.quota_get( response = self.powerscale_api.quota_get(
'/ifs/does_not_exist', 'directory') '/ifs/does_not_exist', 'directory')
self.assertIsNone(response) self.assertIsNone(response)
@@ -650,7 +659,7 @@ class IsilonApiTest(test.TestCase):
m.put('{0}/platform/1/quota/quotas/{1}'.format( m.put('{0}/platform/1/quota/quotas/{1}'.format(
self._mock_url, quota_id), status_code=204) self._mock_url, quota_id), status_code=204)
self.isilon_api.quota_modify_size(quota_id, new_size) self.powerscale_api.quota_modify_size(quota_id, new_size)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
expected_request_body = {'thresholds': {'hard': new_size}} expected_request_body = {'thresholds': {'hard': new_size}}
@@ -663,10 +672,10 @@ class IsilonApiTest(test.TestCase):
quota_id = "ADEF1G" quota_id = "ADEF1G"
new_size = 1024 new_size = 1024
advisory_size = round( advisory_size = round(
(new_size * self.isilon_api_threshold.threshold_limit) / 100) (new_size * self.powerscale_api_threshold.threshold_limit) / 100)
m.put('{0}/platform/1/quota/quotas/{1}'.format( m.put('{0}/platform/1/quota/quotas/{1}'.format(
self._mock_url, quota_id), status_code=204) self._mock_url, quota_id), status_code=204)
self.isilon_api_threshold.quota_modify_size(quota_id, new_size) self.powerscale_api_threshold.quota_modify_size(quota_id, new_size)
self.assertEqual(1, len(m.request_history)) self.assertEqual(1, len(m.request_history))
expected_request_body = {'thresholds': {'hard': new_size, expected_request_body = {'thresholds': {'hard': new_size,
'advisory': advisory_size}} 'advisory': advisory_size}}
@@ -681,7 +690,7 @@ class IsilonApiTest(test.TestCase):
self.assertRaises( self.assertRaises(
requests.exceptions.HTTPError, requests.exceptions.HTTPError,
self.isilon_api.quota_modify_size, self.powerscale_api.quota_modify_size,
quota_id, 1024 quota_id, 1024
) )
@@ -700,7 +709,7 @@ class IsilonApiTest(test.TestCase):
status_code=204 status_code=204
) )
self.isilon_api.quota_set(quota_path, quota_type, quota_size) self.powerscale_api.quota_set(quota_path, quota_type, quota_size)
expected_quota_modify_json = {'thresholds': {'hard': quota_size}} expected_quota_modify_json = {'thresholds': {'hard': quota_size}}
quota_put_json = json.loads(m.request_history[1].body) quota_put_json = json.loads(m.request_history[1].body)
@@ -717,7 +726,7 @@ class IsilonApiTest(test.TestCase):
quota_type = 'directory' quota_type = 'directory'
quota_size = 256 quota_size = 256
self.isilon_api.quota_set(quota_path, quota_type, quota_size) self.powerscale_api.quota_set(quota_path, quota_type, quota_size)
# verify a call is made to create a quota # verify a call is made to create a quota
expected_create_json = { expected_create_json = {
@@ -737,7 +746,7 @@ class IsilonApiTest(test.TestCase):
e = self.assertRaises( e = self.assertRaises(
requests.exceptions.HTTPError, requests.exceptions.HTTPError,
self.isilon_api.quota_set, self.powerscale_api.quota_set,
'/ifs/does_not_exist', 'directory', 2048 '/ifs/does_not_exist', 'directory', 2048
) )
self.assertEqual(400, e.response.status_code) self.assertEqual(400, e.response.status_code)
@@ -746,29 +755,29 @@ class IsilonApiTest(test.TestCase):
sid = {"id": "SID:S-1-22-1-0", sid = {"id": "SID:S-1-22-1-0",
"name": "foo", "name": "foo",
"type": "user"} "type": "user"}
self.isilon_api.auth_lookup_user = mock.MagicMock( self.powerscale_api.auth_lookup_user = mock.MagicMock(
return_value={ return_value={
"mapping": [{"user": {"sid": sid}}] "mapping": [{"user": {"sid": sid}}]
} }
) )
expected_sid = self.isilon_api.get_user_sid('foo') expected_sid = self.powerscale_api.get_user_sid('foo')
self.assertEqual(expected_sid, sid) self.assertEqual(expected_sid, sid)
def test_get_user_sid_wrong_mappings(self): def test_get_user_sid_wrong_mappings(self):
self.isilon_api.auth_lookup_user = mock.MagicMock( self.powerscale_api.auth_lookup_user = mock.MagicMock(
return_value={ return_value={
"mapping": [{"user": {"sid": 'fake_sid1'}}, "mapping": [{"user": {"sid": 'fake_sid1'}},
{"user": {"sid": 'fake_sid2'}}] {"user": {"sid": 'fake_sid2'}}]
} }
) )
expected_sid = self.isilon_api.get_user_sid('foo') expected_sid = self.powerscale_api.get_user_sid('foo')
self.assertIsNone(expected_sid) self.assertIsNone(expected_sid)
def test_get_user_sid_user_not_found(self): def test_get_user_sid_user_not_found(self):
self.isilon_api.auth_lookup_user = mock.MagicMock( self.powerscale_api.auth_lookup_user = mock.MagicMock(
return_value=None return_value=None
) )
expected_sid = self.isilon_api.get_user_sid('foo') expected_sid = self.powerscale_api.get_user_sid('foo')
self.assertIsNone(expected_sid) self.assertIsNone(expected_sid)
@requests_mock.mock() @requests_mock.mock()
@@ -789,7 +798,7 @@ class IsilonApiTest(test.TestCase):
} }
m.get(auth_url, status_code=200, json=auth_json) m.get(auth_url, status_code=200, json=auth_json)
returned_auth_json = self.isilon_api.auth_lookup_user(user) returned_auth_json = self.powerscale_api.auth_lookup_user(user)
self.assertEqual(auth_json, returned_auth_json) self.assertEqual(auth_json, returned_auth_json)
@requests_mock.mock() @requests_mock.mock()
@@ -798,7 +807,7 @@ class IsilonApiTest(test.TestCase):
auth_url = '{0}/platform/1/auth/mapping/users/lookup?user={1}'.format( auth_url = '{0}/platform/1/auth/mapping/users/lookup?user={1}'.format(
self._mock_url, user) self._mock_url, user)
m.get(auth_url, status_code=404) m.get(auth_url, status_code=404)
self.assertIsNone(self.isilon_api.auth_lookup_user(user)) self.assertIsNone(self.powerscale_api.auth_lookup_user(user))
@requests_mock.mock() @requests_mock.mock()
def test_auth_lookup_user_with_backend_error(self, m): def test_auth_lookup_user_with_backend_error(self, m):
@@ -806,7 +815,7 @@ class IsilonApiTest(test.TestCase):
auth_url = '{0}/platform/1/auth/mapping/users/lookup?user={1}'.format( auth_url = '{0}/platform/1/auth/mapping/users/lookup?user={1}'.format(
self._mock_url, user) self._mock_url, user)
m.get(auth_url, status_code=400) m.get(auth_url, status_code=400)
self.assertIsNone(self.isilon_api.auth_lookup_user(user)) self.assertIsNone(self.powerscale_api.auth_lookup_user(user))
def _add_create_directory_response(self, m, path, is_recursive): def _add_create_directory_response(self, m, path, is_recursive):
url = '{0}/namespace{1}?recursive={2}'.format( url = '{0}/namespace{1}?recursive={2}'.format(
@@ -854,87 +863,87 @@ class IsilonApiTest(test.TestCase):
request.headers['x-isi-ifs-copy-source']) request.headers['x-isi-ifs-copy-source'])
def test_modify_nfs_export_access_success(self): def test_modify_nfs_export_access_success(self):
self.isilon_api.send_put_request = mock.MagicMock() self.powerscale_api.send_put_request = mock.MagicMock()
share_id = '123' share_id = '123'
ro_ips = ['10.0.0.1', '10.0.0.2'] ro_ips = ['10.0.0.1', '10.0.0.2']
rw_ips = ['10.0.0.3', '10.0.0.4'] rw_ips = ['10.0.0.3', '10.0.0.4']
self.isilon_api.modify_nfs_export_access(share_id, ro_ips, rw_ips) self.powerscale_api.modify_nfs_export_access(share_id, ro_ips, rw_ips)
expected_url = '{0}/platform/1/protocols/nfs/exports/{1}'.format( expected_url = '{0}/platform/1/protocols/nfs/exports/{1}'.format(
self.isilon_api.host_url, share_id) self.powerscale_api.host_url, share_id)
expected_data = {'read_only_clients': ro_ips, 'clients': rw_ips} expected_data = {'read_only_clients': ro_ips, 'clients': rw_ips}
self.isilon_api.send_put_request.assert_called_once_with( self.powerscale_api.send_put_request.assert_called_once_with(
expected_url, data=expected_data) expected_url, data=expected_data)
def test_modify_nfs_export_access_no_ro_ips(self): def test_modify_nfs_export_access_no_ro_ips(self):
self.isilon_api.send_put_request = mock.MagicMock() self.powerscale_api.send_put_request = mock.MagicMock()
share_id = '123' share_id = '123'
rw_ips = ['10.0.0.3', '10.0.0.4'] rw_ips = ['10.0.0.3', '10.0.0.4']
self.isilon_api.modify_nfs_export_access(share_id, None, rw_ips) self.powerscale_api.modify_nfs_export_access(share_id, None, rw_ips)
expected_url = '{0}/platform/1/protocols/nfs/exports/{1}'.format( expected_url = '{0}/platform/1/protocols/nfs/exports/{1}'.format(
self.isilon_api.host_url, share_id) self.powerscale_api.host_url, share_id)
expected_data = {'clients': rw_ips} expected_data = {'clients': rw_ips}
self.isilon_api.send_put_request.assert_called_once_with( self.powerscale_api.send_put_request.assert_called_once_with(
expected_url, data=expected_data) expected_url, data=expected_data)
def test_modify_nfs_export_access_no_rw_ips(self): def test_modify_nfs_export_access_no_rw_ips(self):
self.isilon_api.send_put_request = mock.MagicMock() self.powerscale_api.send_put_request = mock.MagicMock()
share_id = '123' share_id = '123'
ro_ips = ['10.0.0.1', '10.0.0.2'] ro_ips = ['10.0.0.1', '10.0.0.2']
self.isilon_api.modify_nfs_export_access(share_id, ro_ips, None) self.powerscale_api.modify_nfs_export_access(share_id, ro_ips, None)
expected_url = '{0}/platform/1/protocols/nfs/exports/{1}'.format( expected_url = '{0}/platform/1/protocols/nfs/exports/{1}'.format(
self.isilon_api.host_url, share_id) self.powerscale_api.host_url, share_id)
expected_data = {'read_only_clients': ro_ips} expected_data = {'read_only_clients': ro_ips}
self.isilon_api.send_put_request.assert_called_once_with( self.powerscale_api.send_put_request.assert_called_once_with(
expected_url, data=expected_data) expected_url, data=expected_data)
@mock.patch('requests.Session.request') @mock.patch('requests.Session.request')
def test_request_with_401_response(self, mock_request): def test_request_with_401_response(self, mock_request):
"""Test sending a request with a 401 Unauthorized response.""" """Test sending a request with a 401 Unauthorized response."""
mock_request.return_value.status_code = 401 mock_request.return_value.status_code = 401
self.isilon_api.create_session = mock.MagicMock(return_value=True) self.powerscale_api.create_session = mock.MagicMock(return_value=True)
self.isilon_api.request('GET', 'http://example.com/api/data') self.powerscale_api.request('GET', 'http://example.com/api/data')
self.assertEqual(mock_request.call_count, 2) self.assertEqual(mock_request.call_count, 2)
def test_delete_quota_sends_delete_request(self): def test_delete_quota_sends_delete_request(self):
self.isilon_api.send_delete_request = mock.MagicMock() self.powerscale_api.send_delete_request = mock.MagicMock()
quota_id = '123' quota_id = '123'
self.isilon_api.delete_quota(quota_id) self.powerscale_api.delete_quota(quota_id)
self.isilon_api.send_delete_request.assert_called_once_with( self.powerscale_api.send_delete_request.assert_called_once_with(
'{0}/platform/1/quota/quotas/{1}'.format( '{0}/platform/1/quota/quotas/{1}'.format(
self.isilon_api.host_url, quota_id) self.powerscale_api.host_url, quota_id)
) )
def test_delete_quota_raises_exception_on_error(self): def test_delete_quota_raises_exception_on_error(self):
quota_id = '123' quota_id = '123'
self.isilon_api.send_delete_request = mock.MagicMock( self.powerscale_api.send_delete_request = mock.MagicMock(
side_effect=requests.exceptions.HTTPError) side_effect=requests.exceptions.HTTPError)
self.assertRaises(requests.exceptions.HTTPError, self.assertRaises(requests.exceptions.HTTPError,
self.isilon_api.delete_quota, self.powerscale_api.delete_quota,
quota_id) quota_id)
def test_get_space_stats_success(self): def test_get_space_stats_success(self):
self.isilon_api.send_get_request = mock.MagicMock() self.powerscale_api.send_get_request = mock.MagicMock()
self.isilon_api.send_get_request.return_value.status_code = 200 self.powerscale_api.send_get_request.return_value.status_code = 200
self.isilon_api.send_get_request.return_value.json.return_value = { self.powerscale_api.send_get_request.return_value.json.return_value = {
'stats': [ 'stats': [
{'key': 'ifs.bytes.free', 'value': 1000}, {'key': 'ifs.bytes.free', 'value': 1000},
{'key': 'ifs.bytes.total', 'value': 2000}, {'key': 'ifs.bytes.total', 'value': 2000},
{'key': 'ifs.bytes.used', 'value': 500} {'key': 'ifs.bytes.used', 'value': 500}
] ]
} }
result = self.isilon_api.get_space_stats() result = self.powerscale_api.get_space_stats()
self.assertEqual(result, {'total': 2000, 'free': 1000, 'used': 500}) self.assertEqual(result, {'total': 2000, 'free': 1000, 'used': 500})
def test_get_space_stats_failure(self): def test_get_space_stats_failure(self):
self.isilon_api.send_get_request = mock.MagicMock() self.powerscale_api.send_get_request = mock.MagicMock()
self.isilon_api.send_get_request.return_value.status_code = 400 self.powerscale_api.send_get_request.return_value.status_code = 400
self.assertRaises(exception.ShareBackendException, self.assertRaises(exception.ShareBackendException,
self.isilon_api.get_space_stats) self.powerscale_api.get_space_stats)
def test_get_allocated_space_success(self): def test_get_allocated_space_success(self):
self.isilon_api.send_get_request = mock.MagicMock() self.powerscale_api.send_get_request = mock.MagicMock()
self.isilon_api.send_get_request.return_value.status_code = 200 self.powerscale_api.send_get_request.return_value.status_code = 200
self.isilon_api.send_get_request.return_value.json.return_value = { self.powerscale_api.send_get_request.return_value.json.return_value = {
'quotas': [ 'quotas': [
{ {
'path': '/ifs/home', 'path': '/ifs/home',
@@ -962,86 +971,88 @@ class IsilonApiTest(test.TestCase):
} }
] ]
} }
result = self.isilon_api.get_allocated_space() result = self.powerscale_api.get_allocated_space()
self.assertEqual(result, 2110.0) self.assertEqual(result, 2110.0)
def test_get_allocated_space_failure(self): def test_get_allocated_space_failure(self):
self.isilon_api.send_get_request = mock.MagicMock() self.powerscale_api.send_get_request = mock.MagicMock()
self.isilon_api.send_get_request.return_value.status_code = 400 self.powerscale_api.send_get_request.return_value.status_code = 400
self.assertRaises(exception.ShareBackendException, self.assertRaises(exception.ShareBackendException,
self.isilon_api.get_allocated_space) self.powerscale_api.get_allocated_space)
def test_get_cluster_version_success(self): def test_get_cluster_version_success(self):
self.isilon_api.send_get_request = mock.MagicMock() self.powerscale_api.send_get_request = mock.MagicMock()
self.isilon_api.send_get_request.return_value.status_code = 200 self.powerscale_api.send_get_request.return_value.status_code = 200
self.isilon_api.send_get_request.return_value.json.return_value = { self.powerscale_api.send_get_request.return_value.json.return_value = {
'nodes': [{'release': '1.0'}]} 'nodes': [{'release': '1.0'}]}
version = self.isilon_api.get_cluster_version() version = self.powerscale_api.get_cluster_version()
self.assertEqual(version, '1.0') self.assertEqual(version, '1.0')
self.isilon_api.send_get_request.assert_called_once_with( self.powerscale_api.send_get_request.assert_called_once_with(
'{0}/platform/12/cluster/version'.format(self.isilon_api.host_url) '{0}/platform/12/cluster/version'.format(
self.powerscale_api.host_url)
) )
def test_get_cluster_version_failure(self): def test_get_cluster_version_failure(self):
self.isilon_api.send_get_request = mock.MagicMock() self.powerscale_api.send_get_request = mock.MagicMock()
self.isilon_api.send_get_request.return_value.status_code = 404 self.powerscale_api.send_get_request.return_value.status_code = 404
self.assertRaises(exception.ShareBackendException, self.assertRaises(exception.ShareBackendException,
self.isilon_api.get_cluster_version) self.powerscale_api.get_cluster_version)
self.isilon_api.send_get_request.assert_called_once_with( self.powerscale_api.send_get_request.assert_called_once_with(
'{0}/platform/12/cluster/version'.format(self.isilon_api.host_url) '{0}/platform/12/cluster/version'.format(
self.powerscale_api.host_url)
) )
def test_modify_smb_share_access_with_host_acl_and_smb_permission(self): def test_modify_smb_share_access_with_host_acl_and_smb_permission(self):
self.isilon_api.send_put_request = mock.MagicMock() self.powerscale_api.send_put_request = mock.MagicMock()
share_name = 'my_share' share_name = 'my_share'
host_acl = 'host1,host2' host_acl = 'host1,host2'
smb_permission = 'read' smb_permission = 'read'
self.isilon_api.modify_smb_share_access( self.powerscale_api.modify_smb_share_access(
share_name, host_acl, smb_permission) share_name, host_acl, smb_permission)
expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format( expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format(
self.isilon_api.host_url, share_name) self.powerscale_api.host_url, share_name)
expected_data = {'host_acl': host_acl, 'permissions': smb_permission} expected_data = {'host_acl': host_acl, 'permissions': smb_permission}
self.isilon_api.send_put_request.assert_called_with( self.powerscale_api.send_put_request.assert_called_with(
expected_url, data=expected_data) expected_url, data=expected_data)
def test_modify_smb_share_access_with_host_acl_only(self): def test_modify_smb_share_access_with_host_acl_only(self):
self.isilon_api.send_put_request = mock.MagicMock() self.powerscale_api.send_put_request = mock.MagicMock()
share_name = 'my_share' share_name = 'my_share'
host_acl = 'host1,host2' host_acl = 'host1,host2'
self.isilon_api.modify_smb_share_access(share_name, host_acl) self.powerscale_api.modify_smb_share_access(share_name, host_acl)
expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format( expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format(
self.isilon_api.host_url, share_name) self.powerscale_api.host_url, share_name)
expected_data = {'host_acl': host_acl} expected_data = {'host_acl': host_acl}
self.isilon_api.send_put_request.assert_called_with( self.powerscale_api.send_put_request.assert_called_with(
expected_url, data=expected_data) expected_url, data=expected_data)
def test_modify_smb_share_access_with_smb_permission_only(self): def test_modify_smb_share_access_with_smb_permission_only(self):
self.isilon_api.send_put_request = mock.MagicMock() self.powerscale_api.send_put_request = mock.MagicMock()
share_name = 'my_share' share_name = 'my_share'
smb_permission = 'read' smb_permission = 'read'
self.isilon_api.modify_smb_share_access( self.powerscale_api.modify_smb_share_access(
share_name, permissions=smb_permission) share_name, permissions=smb_permission)
expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format( expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format(
self.isilon_api.host_url, share_name) self.powerscale_api.host_url, share_name)
expected_data = {'permissions': smb_permission} expected_data = {'permissions': smb_permission}
self.isilon_api.send_put_request.assert_called_with( self.powerscale_api.send_put_request.assert_called_with(
expected_url, data=expected_data) expected_url, data=expected_data)
def test_modify_smb_share_access_with_no_arguments(self): def test_modify_smb_share_access_with_no_arguments(self):
self.isilon_api.send_put_request = mock.MagicMock() self.powerscale_api.send_put_request = mock.MagicMock()
share_name = 'my_share' share_name = 'my_share'
self.isilon_api.modify_smb_share_access(share_name) self.powerscale_api.modify_smb_share_access(share_name)
expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format( expected_url = '{0}/platform/1/protocols/smb/shares/{1}'.format(
self.isilon_api.host_url, share_name) self.powerscale_api.host_url, share_name)
expected_data = {} expected_data = {}
self.isilon_api.send_put_request.assert_called_with( self.powerscale_api.send_put_request.assert_called_with(
expected_url, data=expected_data) expected_url, data=expected_data)
def test_modify_smb_share_access_with_http_error(self): def test_modify_smb_share_access_with_http_error(self):
self.isilon_api.send_put_request = mock.MagicMock( self.powerscale_api.send_put_request = mock.MagicMock(
side_effect=requests.exceptions.HTTPError side_effect=requests.exceptions.HTTPError
) )
share_name = 'my_share' share_name = 'my_share'
@@ -1049,5 +1060,5 @@ class IsilonApiTest(test.TestCase):
smb_permission = 'read' smb_permission = 'read'
self.assertRaises(requests.exceptions.HTTPError, self.assertRaises(requests.exceptions.HTTPError,
self.isilon_api.modify_smb_share_access, self.powerscale_api.modify_smb_share_access,
share_name, host_acl, smb_permission) share_name, host_acl, smb_permission)

View File

@@ -0,0 +1,13 @@
---
features:
- |
Rebrand from Isilon to PowerScale includes changing of tag names, directory
structure, file names and documentation.
upgrade:
- |
Dell PowerScale Driver was previously the EMC Isilon Driver. If the
extra-spec``share_backend_name`` was set to ``isilon`` in share types
in the past, this needs to be changed to ``powerscale``.
``emc_share_backend`` configuration option must be switched from
``isilon`` to ``powerscale`` in manila.conf when you add the storage
backend.

View File

@@ -76,7 +76,7 @@ oslo.policy.policies =
manila.share.drivers.dell_emc.plugins = manila.share.drivers.dell_emc.plugins =
vnx = manila.share.drivers.dell_emc.plugins.vnx.connection:VNXStorageConnection vnx = manila.share.drivers.dell_emc.plugins.vnx.connection:VNXStorageConnection
unity = manila.share.drivers.dell_emc.plugins.unity.connection:UnityStorageConnection unity = manila.share.drivers.dell_emc.plugins.unity.connection:UnityStorageConnection
isilon = manila.share.drivers.dell_emc.plugins.isilon.isilon:IsilonStorageConnection powerscale = manila.share.drivers.dell_emc.plugins.powerscale.powerscale:PowerScaleStorageConnection
powermax = manila.share.drivers.dell_emc.plugins.powermax.connection:PowerMaxStorageConnection powermax = manila.share.drivers.dell_emc.plugins.powermax.connection:PowerMaxStorageConnection
powerstore = manila.share.drivers.dell_emc.plugins.powerstore.connection:PowerStoreStorageConnection powerstore = manila.share.drivers.dell_emc.plugins.powerstore.connection:PowerStoreStorageConnection
powerflex = manila.share.drivers.dell_emc.plugins.powerflex.connection:PowerFlexStorageConnection powerflex = manila.share.drivers.dell_emc.plugins.powerflex.connection:PowerFlexStorageConnection