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
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
based driver which is designed to use different plugins to manage different EMC
storage products.
based driver which is designed to use different plugins to manage different
Dell storage products.
The Isilon manila driver is a plugin for the EMC manila driver framework which
allows manila to interface with an Isilon backend to provide a shared
filesystem. The EMC driver framework with the Isilon plugin is referred to as
the "Isilon Driver" in this document.
The PowerScale manila driver is a plugin for the EMC manila driver framework
which allows manila to interface with an PowerScale backend to provide a shared
filesystem. The EMC driver framework with the PowerScale plugin is referred to
as the "PowerScale Driver" in this document.
This Isilon Driver interfaces with an Isilon cluster via the REST Isilon
Platform API (PAPI) and the RESTful Access to Namespace API (RAN).
This PowerScale Driver interfaces with an PowerScale cluster via the REST
PowerScale Platform API (PAPI) and the RESTful Access to Namespace API (RAN).
Requirements
------------
- Isilon cluster running OneFS 7.2 or higher
- PowerScale cluster running OneFS 9.10 or higher
Supported Operations
--------------------
The following operations are supported on an Isilon cluster:
The following operations are supported on an PowerScale cluster:
* Create 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
for the Isilon driver:
for the PowerScale driver:
* share_driver = manila.share.drivers.dell_emc.driver.EMCShareDriver
* driver_handles_share_servers = False
* emc_share_backend = isilon
* emc_nas_server = <IP address of Isilon cluster>
* emc_nas_server_port = <port to use for Isilon cluster (optional)>
* emc_share_backend = powerscale
* emc_nas_server = <IP address of PowerScale cluster>
* emc_nas_server_port = <port to use for PowerScale cluster (optional)>
* emc_nas_login = <username>
* emc_nas_password = <password>
* 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
effect.
Restart of :term:`manila-share` service is needed for the configuration changes
to take effect.
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.
@@ -87,10 +87,10 @@ The :mod:`manila.share.drivers.dell_emc.driver` Module
:undoc-members:
: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:
:members:
:undoc-members:

View File

@@ -86,8 +86,8 @@ each back end.
container_driver
zfs_on_linux_driver
netapp_cluster_mode_driver
emc_isilon_driver
emc_vnx_driver
dell_emc_powerscale_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-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 | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
| 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) | \- | \- | \- |
+----------------------------------------+-----------------------+-----------------------+--------------------------+--------------------------+------------------------+-----------------------------------+--------------------------+--------------------+--------------------+
@@ -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) | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
| 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) | \- | \- | \- | \- | \- | \- | \- | \- | \- |
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
@@ -199,17 +199,17 @@ Mapping of share drivers and security services support
+----------------------------------------+------------------+-----------------+------------------+
| 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 | \- | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+
@@ -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 |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+
| 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 | \- | \- | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+-------------------------+--------------------------+

View File

@@ -87,7 +87,6 @@ master_doc = 'index'
# General information about the project.
copyright = '2010-present, Manila contributors'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
@@ -175,6 +174,9 @@ html_theme_options = {
# so a file named "default.css" will overwrite the builtin "default.css".
# 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,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
@@ -213,7 +215,6 @@ html_theme_options = {
# Output file base name for HTML help builder.
htmlhelp_basename = 'maniladoc'
# -- Options for LaTeX output -------------------------------------------------
# The paper size ('letter' or 'a4').

View File

@@ -23,7 +23,7 @@ Share drivers
drivers/lvm-driver.rst
drivers/zfs-on-linux-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-hsp-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`
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`
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
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
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
Shared File Systems service to interface with an Isilon back end to
provide a shared filesystem. The EMC driver framework with the Isilon
plug-in is referred to as the ``Isilon Driver`` in this document.
The PowerScale driver is a plug-in for the EMC framework which allows the
Shared File Systems service to interface with an PowerScale back end to
provide a shared filesystem. The EMC driver framework with the PowerScale
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).
Requirements
@@ -52,13 +53,13 @@ Back end configuration
~~~~~~~~~~~~~~~~~~~~~~
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
share_driver = manila.share.drivers.emc.driver.EMCShareDriver
emc_share_backend = isilon
emc_nas_server = <IP address of Isilon cluster>
emc_share_backend = powerscale
emc_nas_server = <IP address of PowerScale cluster>
emc_nas_login = <username>
emc_nas_password = <password>
@@ -75,7 +76,7 @@ Add the parameter below to set an advisory limit.
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.

View File

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

View File

@@ -42,7 +42,7 @@ EMC_NAS_OPTS = [
help='Use secure connection to server.'),
cfg.StrOpt('emc_share_backend',
ignore_case=True,
choices=['isilon', 'vnx', 'unity', 'powermax',
choices=['powerscale', 'isilon', 'vnx', 'unity', 'powermax',
'powerstore', 'powerflex'],
help='Share backend.'),
cfg.StrOpt('emc_nas_root_dir',
@@ -81,6 +81,11 @@ class EMCShareDriver(driver.ShareDriver):
if self.backend_name == 'vnx':
LOG.warning('Dell EMC VNX share driver has been deprecated and is '
'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.backend_name,
configuration=self.configuration)

View File

@@ -14,7 +14,7 @@
# under the License.
"""
Isilon specific NAS backend plugin.
PowerScale specific NAS backend plugin.
"""
import os
@@ -26,7 +26,7 @@ from manila.common import constants as const
from manila import exception
from manila.i18n import _
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:
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.2 - Add support for ensure shares
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
@@ -53,11 +54,11 @@ POWERSCALE_OPTS = [
]
class IsilonStorageConnection(base.StorageConnection):
"""Implements Isilon specific functionality for EMC Manila driver."""
class PowerScaleStorageConnection(base.StorageConnection):
"""Implements PowerScale specific functionality for EMC Manila driver."""
def __init__(self, *args, **kwargs):
super(IsilonStorageConnection, self).__init__(*args, **kwargs)
super(PowerScaleStorageConnection, self).__init__(*args, **kwargs)
LOG.debug('Setting up attributes for Manila '
'Dell PowerScale Driver.')
if 'configuration' in kwargs:
@@ -75,7 +76,7 @@ class IsilonStorageConnection(base.StorageConnection):
self._shares = {}
self._snapshots = {}
self._isilon_api = None
self._powerscale_api = None
self.driver_handles_share_servers = False
self.ipv6_implemented = True
# props for share status update
@@ -104,7 +105,7 @@ class IsilonStorageConnection(base.StorageConnection):
# apply directory quota based on share size
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)
return location
@@ -118,7 +119,7 @@ class IsilonStorageConnection(base.StorageConnection):
# Clone snapshot to new location
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
@@ -129,7 +130,7 @@ class IsilonStorageConnection(base.StorageConnection):
container_path = self._get_container_path(share)
self._create_directory(container_path)
# 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:
message = (
_('The requested NFS share "%(share)s" was not created.') %
@@ -146,7 +147,7 @@ class IsilonStorageConnection(base.StorageConnection):
container_path = self._get_container_path(share)
self._create_directory(container_path)
# Create smb share
share_created = self._isilon_api.create_smb_share(
share_created = self._powerscale_api.create_smb_share(
share['name'], container_path)
if not share_created:
message = (
@@ -159,7 +160,7 @@ class IsilonStorageConnection(base.StorageConnection):
def _create_directory(self, path, recursive=False):
"""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:
message = (
_('Failed to create directory "%(dir)s".') %
@@ -171,7 +172,7 @@ class IsilonStorageConnection(base.StorageConnection):
"""Is called to create snapshot."""
LOG.debug(f'Creating snapshot {snapshot["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)
if not snap_created:
message = (
@@ -201,10 +202,10 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_quota(self, path):
"""Is called to remove quota."""
quota = self._isilon_api.quota_get(path, 'directory')
quota = self._powerscale_api.quota_get(path, 'directory')
if quota:
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:
message = (
_('Failed to delete quota "%(quota_id)s" for '
@@ -216,10 +217,10 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_directory(self, path):
"""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:
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:
message = (
_('Failed to delete directory "%(dir)s".') %
@@ -230,7 +231,7 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_nfs_share(self, 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))
if share_id is None:
@@ -239,7 +240,7 @@ class IsilonStorageConnection(base.StorageConnection):
LOG.warning(lw, share['name'])
else:
# 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:
message = _('Error deleting NFS share: %s') % share['name']
LOG.error(message)
@@ -247,13 +248,14 @@ class IsilonStorageConnection(base.StorageConnection):
def _delete_cifs_share(self, 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:
lw = ('Attempted to delete CIFS Share "%s", but the share does '
'not appear to exist.')
LOG.warning(lw, share['name'])
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:
message = _('Error deleting CIFS share: %s') % share['name']
LOG.error(message)
@@ -262,7 +264,7 @@ class IsilonStorageConnection(base.StorageConnection):
def delete_snapshot(self, context, snapshot, share_server):
"""Is called to remove snapshot."""
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:
message = (
_('Failed to delete snapshot "%(snap)s".') %
@@ -280,7 +282,7 @@ class IsilonStorageConnection(base.StorageConnection):
'name': share['name'], 'size': new_size
})
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)
def allow_access(self, context, share, access, share_server):
@@ -295,7 +297,7 @@ class IsilonStorageConnection(base.StorageConnection):
"""Check for setup error."""
def connect(self, emc_share_driver, context):
"""Connect to an Isilon cluster."""
"""Connect to an PowerScale cluster."""
LOG.debug('Reading configuration parameters for Manila'
' Dell PowerScale Driver.')
config = emc_share_driver.configuration
@@ -320,13 +322,13 @@ class IsilonStorageConnection(base.StorageConnection):
if self._verify_ssl_cert:
self._ssl_cert_path = config.safe_get("emc_ssl_cert_path")
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._verify_ssl_cert, self._ssl_cert_path,
self._dir_permission,
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)
# configuration for share status update
@@ -367,11 +369,11 @@ class IsilonStorageConnection(base.StorageConnection):
self.max_over_subscription_ratio,
'thin_provisioning': True,
}
spaces = self._isilon_api.get_space_stats()
spaces = self._powerscale_api.get_space_stats()
if spaces:
pool_stat['total_capacity_gb'] = spaces['total'] // 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
stats_dict['pools'] = [pool_stat]
@@ -415,7 +417,7 @@ class IsilonStorageConnection(base.StorageConnection):
elif rule['access_level'] == const.ACCESS_LEVEL_RO:
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))
if export_id is None:
# share does not exist on backend (set all rules to error state)
@@ -424,7 +426,7 @@ class IsilonStorageConnection(base.StorageConnection):
LOG.error(message)
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))
if not r:
return rule_state_map
@@ -449,20 +451,22 @@ class IsilonStorageConnection(base.StorageConnection):
) % {'type': rule['access_type']})
LOG.error(message)
rule_state_map.update({rule['access_id']: {'state': 'error'}})
ips = self._get_cifs_ip_list(ip_access_rules, rule_state_map)
user_permissions = self._get_cifs_user_permissions(
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'],
host_acl=ips,
permissions=user_permissions)
if not share_updated:
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)
for rule in access_rules:
rule_state_map[rule['access_id']] = {
@@ -490,9 +494,9 @@ class IsilonStorageConnection(base.StorageConnection):
cifs_user_permissions = []
for rule in access_rules:
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:
smb_permission = isilon_api.SmbPermission.ro
smb_permission = powerscale_api.SmbPermission.ro
else:
message = ('Only RW and RO access levels are supported '
'for CIFS user access.')
@@ -500,7 +504,7 @@ class IsilonStorageConnection(base.StorageConnection):
rule_state_map.update({rule['access_id']: {'state': 'error'}})
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:
cifs_user_permissions.append({
'permission': smb_permission.value,
@@ -521,7 +525,7 @@ class IsilonStorageConnection(base.StorageConnection):
:returns: A dictionary containing driver-specific 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,
'cluster_version': cluster_version,
'rest_server': self._server,
@@ -538,7 +542,8 @@ class IsilonStorageConnection(base.StorageConnection):
for share in shares:
if share['share_proto'] == 'NFS':
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:
location = self._format_nfs_path(container_path)
updates[share['id']] = {
@@ -549,7 +554,8 @@ class IsilonStorageConnection(base.StorageConnection):
else:
LOG.warning(f'NFS Share {share["name"]} is not found.')
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:
location = self._format_smb_path(share['name'])
updates[share['id']] = {

View File

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

View File

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

View File

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

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 =
vnx = manila.share.drivers.dell_emc.plugins.vnx.connection:VNXStorageConnection
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
powerstore = manila.share.drivers.dell_emc.plugins.powerstore.connection:PowerStoreStorageConnection
powerflex = manila.share.drivers.dell_emc.plugins.powerflex.connection:PowerFlexStorageConnection