Merge "Add EMC Unity Driver for Manila"
This commit is contained in:
commit
367d54335e
126
doc/source/devref/emc_unity_driver.rst
Normal file
126
doc/source/devref/emc_unity_driver.rst
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
..
|
||||||
|
Copyright (c) 2014 EMC Corporation
|
||||||
|
All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
not use this file except in compliance with the License. You may obtain
|
||||||
|
a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
Unity Driver
|
||||||
|
============
|
||||||
|
|
||||||
|
EMC manila driver framework (EMCShareDriver) utilizes the EMC storage products
|
||||||
|
to provide the 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.
|
||||||
|
|
||||||
|
Unity plugin is the plugin which manages the Unity Storage System to provide
|
||||||
|
shared filesystems. EMC driver framework with Unity plugin is referred to as
|
||||||
|
Unity driver in this document.
|
||||||
|
|
||||||
|
This driver performs the operations on Unity by REST API. Each backend manages
|
||||||
|
one Unity Storage System. Multiple manila backends need to be configured to
|
||||||
|
manage multiple Unity Storage Systems.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
- Unity OE 4.0.1 or higher.
|
||||||
|
- StorOps 0.2.17 or higher is installed on Manila node.
|
||||||
|
- Following licenses are activated on Unity:
|
||||||
|
* CIFS/SMB Support
|
||||||
|
* Network File System (NFS)
|
||||||
|
* Thin Provisioning
|
||||||
|
* Fiber Channel (FC)
|
||||||
|
* Internet Small Computer System Interface (iSCSI)
|
||||||
|
|
||||||
|
|
||||||
|
Supported Operations
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
In detail, users are allowed to do following operation with EMC Unity
|
||||||
|
Storage Systems.
|
||||||
|
|
||||||
|
* Create/delete a NFS share.
|
||||||
|
* Create/delete a CIFS share.
|
||||||
|
* Extend the size of a share.
|
||||||
|
* Modify the host access privilege of a NFS share.
|
||||||
|
* Modify the user access privilege of a CIFS share.
|
||||||
|
* Take/Delete snapshot of a share.
|
||||||
|
* Create a new share from snapshot.
|
||||||
|
|
||||||
|
|
||||||
|
Supported Network Topologies
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
flat, VLAN
|
||||||
|
|
||||||
|
|
||||||
|
Pre-Configurations
|
||||||
|
------------------
|
||||||
|
|
||||||
|
On Manila Node
|
||||||
|
``````````````
|
||||||
|
|
||||||
|
StorOps library is required to run Unity driver.
|
||||||
|
Please install it with the pip command.
|
||||||
|
You may need root privilege to install python libraries.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pip install storops
|
||||||
|
|
||||||
|
|
||||||
|
Configurations
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Following configurations are introduced for the Unity plugin.
|
||||||
|
|
||||||
|
* emc_interface_ports: White list of the ports to be used for connection.
|
||||||
|
Wild card character is supported.
|
||||||
|
Examples: spa_eth1, spa_*, *
|
||||||
|
* emc_nas_server_pool: The pool used to persist the meta-data of created
|
||||||
|
NAS servers. Wild card character is supported.
|
||||||
|
Examples: pool_1, pool_*, *
|
||||||
|
|
||||||
|
|
||||||
|
API Implementations
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Following driver features are implemented in the plugin.
|
||||||
|
|
||||||
|
* create_share: Create a share and export it based on the protocol used
|
||||||
|
(NFS or CIFS).
|
||||||
|
* create_share_from_snapshot: Create a share from a snapshot - clone a
|
||||||
|
snapshot.
|
||||||
|
* delete_share: Delete a share.
|
||||||
|
* extend_share: Extend the maximum size of a share.
|
||||||
|
* create_snapshot: Create a snapshot for the specified share.
|
||||||
|
* delete_snapshot: Delete the snapshot of the share.
|
||||||
|
* update_access: recover, add or delete user/host access to a share.
|
||||||
|
* allow_access: Allow access (read write/read only) of a user to a
|
||||||
|
CIFS share. Allow access (read write/read only) of a host to a NFS
|
||||||
|
share.
|
||||||
|
* deny_access: Remove access (read write/read only) of a user from
|
||||||
|
a CIFS share. Remove access (read write/read only) of a host from a
|
||||||
|
NFS share.
|
||||||
|
* ensure_share: Check whether share exists or not.
|
||||||
|
* update_share_stats: Retrieve share related statistics from Unity.
|
||||||
|
* get_network_allocations_number: Returns number of network allocations for
|
||||||
|
creating VIFs.
|
||||||
|
* setup_server: Set up and configures share server with given network
|
||||||
|
parameters.
|
||||||
|
* teardown_server: Tear down the share server.
|
||||||
|
|
||||||
|
Restrictions
|
||||||
|
------------
|
||||||
|
|
||||||
|
* EMC Unity does not support the same IP in different VLANs.
|
@ -108,6 +108,7 @@ Share backends
|
|||||||
netapp_cluster_mode_driver
|
netapp_cluster_mode_driver
|
||||||
emc_isilon_driver
|
emc_isilon_driver
|
||||||
emc_vnx_driver
|
emc_vnx_driver
|
||||||
|
emc_unity_driver
|
||||||
generic_driver
|
generic_driver
|
||||||
glusterfs_driver
|
glusterfs_driver
|
||||||
glusterfs_native_driver
|
glusterfs_native_driver
|
||||||
|
@ -41,6 +41,8 @@ Mapping of share drivers and share features support
|
|||||||
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
||||||
| EMC VNX | J | \- | \- | \- | J | J | \- |
|
| EMC VNX | J | \- | \- | \- | J | J | \- |
|
||||||
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
||||||
|
| EMC Unity | N | \- | N | \- | N | N | \- |
|
||||||
|
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
||||||
| EMC Isilon | K | \- | M | \- | K | K | \- |
|
| EMC Isilon | K | \- | M | \- | K | K | \- |
|
||||||
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
||||||
| Red Hat GlusterFS | J | \- | \- | \- | volume layout (L) | volume layout (L) | \- |
|
| Red Hat GlusterFS | J | \- | \- | \- | volume layout (L) | volume layout (L) | \- |
|
||||||
@ -86,6 +88,8 @@ Mapping of share drivers and share access rules support
|
|||||||
+----------------------------------------+--------------+----------------+------------+--------------+--------------+----------------+------------+------------+
|
+----------------------------------------+--------------+----------------+------------+--------------+--------------+----------------+------------+------------+
|
||||||
| EMC VNX | NFS (J) | CIFS (J) | \- | \- | NFS (L) | CIFS (L) | \- | \- |
|
| EMC VNX | NFS (J) | CIFS (J) | \- | \- | NFS (L) | CIFS (L) | \- | \- |
|
||||||
+----------------------------------------+--------------+----------------+------------+--------------+--------------+----------------+------------+------------+
|
+----------------------------------------+--------------+----------------+------------+--------------+--------------+----------------+------------+------------+
|
||||||
|
| EMC Unity | NFS (N) | CIFS (N) | \- | \- | NFS (N) | CIFS (N) | \- | \- |
|
||||||
|
+----------------------------------------+--------------+----------------+------------+--------------+--------------+----------------+------------+------------+
|
||||||
| EMC Isilon | NFS,CIFS (K) | CIFS (M) | \- | \- | NFS (M) | CIFS (M) | \- | \- |
|
| EMC Isilon | NFS,CIFS (K) | CIFS (M) | \- | \- | NFS (M) | CIFS (M) | \- | \- |
|
||||||
+----------------------------------------+--------------+----------------+------------+--------------+--------------+----------------+------------+------------+
|
+----------------------------------------+--------------+----------------+------------+--------------+--------------+----------------+------------+------------+
|
||||||
| Red Hat GlusterFS | NFS (J) | \- | \- | \- | \- | \- | \- | \- |
|
| Red Hat GlusterFS | NFS (J) | \- | \- | \- | \- | \- | \- | \- |
|
||||||
@ -129,6 +133,8 @@ Mapping of share drivers and security services support
|
|||||||
+----------------------------------------+------------------+-----------------+------------------+
|
+----------------------------------------+------------------+-----------------+------------------+
|
||||||
| EMC VNX | J | \- | \- |
|
| EMC VNX | J | \- | \- |
|
||||||
+----------------------------------------+------------------+-----------------+------------------+
|
+----------------------------------------+------------------+-----------------+------------------+
|
||||||
|
| EMC Unity | N | \- | \- |
|
||||||
|
+----------------------------------------+------------------+-----------------+------------------+
|
||||||
| EMC Isilon | \- | \- | \- |
|
| EMC Isilon | \- | \- | \- |
|
||||||
+----------------------------------------+------------------+-----------------+------------------+
|
+----------------------------------------+------------------+-----------------+------------------+
|
||||||
| Red Hat GlusterFS | \- | \- | \- |
|
| Red Hat GlusterFS | \- | \- | \- |
|
||||||
@ -172,6 +178,8 @@ Mapping of share drivers and common capabilities
|
|||||||
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+
|
||||||
| EMC VNX | J | \- | \- | \- | \- | L | \- |
|
| EMC VNX | J | \- | \- | \- | \- | L | \- |
|
||||||
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+
|
||||||
|
| EMC Unity | N | \- | \- | \- | N | \- | \- |
|
||||||
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+
|
||||||
| EMC Isilon | \- | K | \- | \- | \- | L | \- |
|
| EMC Isilon | \- | K | \- | \- | \- | L | \- |
|
||||||
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+
|
||||||
| Red Hat GlusterFS | \- | J | \- | \- | \- | L | \- |
|
| Red Hat GlusterFS | \- | J | \- | \- | \- | L | \- |
|
||||||
|
@ -554,6 +554,10 @@ class ShareTypeInUse(ManilaException):
|
|||||||
"shares present with the type.")
|
"shares present with the type.")
|
||||||
|
|
||||||
|
|
||||||
|
class IPAddressInUse(InUse):
|
||||||
|
message = _("IP address %(ip)s is already used.")
|
||||||
|
|
||||||
|
|
||||||
class ShareTypeExists(ManilaException):
|
class ShareTypeExists(ManilaException):
|
||||||
message = _("Share Type %(id)s already exists.")
|
message = _("Share Type %(id)s already exists.")
|
||||||
|
|
||||||
@ -645,6 +649,10 @@ class EMCVnxInvalidMoverID(ManilaException):
|
|||||||
message = _("Invalid mover or vdm %(id)s.")
|
message = _("Invalid mover or vdm %(id)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class EMCUnityError(ShareBackendException):
|
||||||
|
message = _("%(err)s")
|
||||||
|
|
||||||
|
|
||||||
class HPE3ParInvalidClient(Invalid):
|
class HPE3ParInvalidClient(Invalid):
|
||||||
message = _("%(err)s")
|
message = _("%(err)s")
|
||||||
|
|
||||||
|
@ -26,10 +26,8 @@ from oslo_log import log
|
|||||||
from manila.share import driver
|
from manila.share import driver
|
||||||
from manila.share.drivers.emc import plugin_manager as manager
|
from manila.share.drivers.emc import plugin_manager as manager
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
EMC_NAS_OPTS = [
|
EMC_NAS_OPTS = [
|
||||||
cfg.StrOpt('emc_nas_login',
|
cfg.StrOpt('emc_nas_login',
|
||||||
help='User name for the EMC server.'),
|
help='User name for the EMC server.'),
|
||||||
@ -44,15 +42,18 @@ EMC_NAS_OPTS = [
|
|||||||
default=True,
|
default=True,
|
||||||
help='Use secure connection to server.'),
|
help='Use secure connection to server.'),
|
||||||
cfg.StrOpt('emc_share_backend',
|
cfg.StrOpt('emc_share_backend',
|
||||||
|
ignore_case=True,
|
||||||
|
choices=['isilon', 'vnx', 'unity'],
|
||||||
help='Share backend.'),
|
help='Share backend.'),
|
||||||
cfg.StrOpt('emc_nas_server_container',
|
cfg.StrOpt('emc_nas_server_container',
|
||||||
default='server_2',
|
|
||||||
help='Container of share servers.'),
|
help='Container of share servers.'),
|
||||||
cfg.StrOpt('emc_nas_pool_names',
|
cfg.ListOpt('emc_nas_pool_names',
|
||||||
deprecated_name='emc_nas_pool_name',
|
deprecated_name='emc_nas_pool_name',
|
||||||
help='EMC pool names.'),
|
help='EMC pool names.'),
|
||||||
cfg.StrOpt('emc_nas_root_dir',
|
cfg.StrOpt('emc_nas_root_dir',
|
||||||
help='The root directory where shares will be located.'),
|
help='The root directory where shares will be located.'),
|
||||||
|
cfg.StrOpt('emc_nas_server_pool',
|
||||||
|
help='Pool to persist the meta-data of NAS server.'),
|
||||||
cfg.ListOpt('emc_interface_ports',
|
cfg.ListOpt('emc_interface_ports',
|
||||||
help='Comma separated list specifying the ports that can be '
|
help='Comma separated list specifying the ports that can be '
|
||||||
'used for share server interfaces. Members of the list '
|
'used for share server interfaces. Members of the list '
|
||||||
@ -65,6 +66,7 @@ CONF.register_opts(EMC_NAS_OPTS)
|
|||||||
|
|
||||||
class EMCShareDriver(driver.ShareDriver):
|
class EMCShareDriver(driver.ShareDriver):
|
||||||
"""EMC specific NAS driver. Allows for NFS and CIFS NAS storage usage."""
|
"""EMC specific NAS driver. Allows for NFS and CIFS NAS storage usage."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.configuration = kwargs.get('configuration', None)
|
self.configuration = kwargs.get('configuration', None)
|
||||||
if self.configuration:
|
if self.configuration:
|
||||||
|
0
manila/share/drivers/emc/plugins/unity/__init__.py
Normal file
0
manila/share/drivers/emc/plugins/unity/__init__.py
Normal file
261
manila/share/drivers/emc/plugins/unity/client.py
Normal file
261
manila/share/drivers/emc/plugins/unity/client.py
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import random
|
||||||
|
import six
|
||||||
|
|
||||||
|
from oslo_log import log
|
||||||
|
from oslo_utils import importutils
|
||||||
|
|
||||||
|
storops = importutils.try_import('storops')
|
||||||
|
if storops:
|
||||||
|
from storops import exception as storops_ex
|
||||||
|
from storops.unity import enums
|
||||||
|
|
||||||
|
from manila.common import constants as const
|
||||||
|
from manila import exception
|
||||||
|
from manila.i18n import _, _LI, _LE
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class UnityClient(object):
|
||||||
|
def __init__(self, host, username, password):
|
||||||
|
if storops is None:
|
||||||
|
LOG.error(_LE('StorOps is required to run EMC Unity driver.'))
|
||||||
|
self.system = storops.UnitySystem(host, username, password)
|
||||||
|
|
||||||
|
def create_cifs_share(self, resource, share_name):
|
||||||
|
"""Create CIFS share from the resource.
|
||||||
|
|
||||||
|
:param resource: either UnityFilesystem or UnitySnap object
|
||||||
|
:param share_name: CIFS share name
|
||||||
|
:return: UnityCifsShare object
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
share = resource.create_cifs_share(share_name)
|
||||||
|
try:
|
||||||
|
# bug on unity: the enable ace API has bug for snap
|
||||||
|
# based share. Log the internal error if it happens.
|
||||||
|
share.enable_ace()
|
||||||
|
except storops_ex.UnityException:
|
||||||
|
msg = _LE('Failed to enabled ACE for share: {}.')
|
||||||
|
LOG.exception(msg.format(share_name))
|
||||||
|
return share
|
||||||
|
except storops_ex.UnitySmbShareNameExistedError:
|
||||||
|
return self.get_share(share_name, 'CIFS')
|
||||||
|
|
||||||
|
def create_nfs_share(self, resource, share_name):
|
||||||
|
"""Create NFS share from the resource.
|
||||||
|
|
||||||
|
:param resource: either UnityFilesystem or UnitySnap object
|
||||||
|
:param share_name: NFS share name
|
||||||
|
:return: UnityNfsShare object
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return resource.create_nfs_share(share_name)
|
||||||
|
except storops_ex.UnityNfsShareNameExistedError:
|
||||||
|
return self.get_share(share_name, 'NFS')
|
||||||
|
|
||||||
|
def get_share(self, name, share_proto):
|
||||||
|
# Validate the share protocol
|
||||||
|
proto = share_proto.upper()
|
||||||
|
|
||||||
|
if proto == 'CIFS':
|
||||||
|
return self.system.get_cifs_share(name=name)
|
||||||
|
elif proto == 'NFS':
|
||||||
|
return self.system.get_nfs_share(name=name)
|
||||||
|
else:
|
||||||
|
raise exception.BadConfigurationException(
|
||||||
|
reason=_('Invalid NAS protocol supplied: %s.') % share_proto)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_share(share):
|
||||||
|
share.delete()
|
||||||
|
|
||||||
|
def create_filesystem(self, pool, nas_server, share_name, size, proto):
|
||||||
|
try:
|
||||||
|
return pool.create_filesystem(nas_server,
|
||||||
|
share_name,
|
||||||
|
size,
|
||||||
|
proto=proto)
|
||||||
|
except storops_ex.UnityFileSystemNameAlreadyExisted:
|
||||||
|
LOG.debug('Filesystem %s already exists, '
|
||||||
|
'ignoring filesystem creation.', share_name)
|
||||||
|
return self.system.get_filesystem(name=share_name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_filesystem(filesystem):
|
||||||
|
try:
|
||||||
|
filesystem.delete()
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
LOG.info(_LI('Filesystem %s is already removed.'), filesystem.name)
|
||||||
|
|
||||||
|
def create_nas_server(self, name, sp, pool):
|
||||||
|
try:
|
||||||
|
return self.system.create_nas_server(name, sp, pool)
|
||||||
|
except storops_ex.UnityNasServerNameUsedError:
|
||||||
|
LOG.info(_LI('Share server %s already exists, ignoring share '
|
||||||
|
'server creation.'), name)
|
||||||
|
return self.get_nas_server(name)
|
||||||
|
|
||||||
|
def get_nas_server(self, name):
|
||||||
|
try:
|
||||||
|
return self.system.get_nas_server(name=name)
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
LOG.info(_LI('NAS server %s not found.'), name)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def delete_nas_server(self, name, username=None, password=None):
|
||||||
|
try:
|
||||||
|
nas_server = self.get_nas_server(name=name)
|
||||||
|
nas_server.delete(username=username, password=password)
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
LOG.info(_LI('NAS server %s not found.'), name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_dns_server(nas_server, domain, dns_ip):
|
||||||
|
try:
|
||||||
|
nas_server.create_dns_server(domain, dns_ip)
|
||||||
|
except storops_ex.UnityOneDnsPerNasServerError:
|
||||||
|
LOG.info(_LI('DNS server %s already exists, '
|
||||||
|
'ignoring DNS server creation.'), domain)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_interface(nas_server, ip_addr, netmask, gateway, ports,
|
||||||
|
vlan_id=None):
|
||||||
|
port_list = list(ports)
|
||||||
|
random.shuffle(port_list)
|
||||||
|
try:
|
||||||
|
nas_server.create_file_interface(port_list[0],
|
||||||
|
ip_addr,
|
||||||
|
netmask=netmask,
|
||||||
|
gateway=gateway,
|
||||||
|
vlan_id=vlan_id)
|
||||||
|
except storops_ex.UnityIpAddressUsedError:
|
||||||
|
raise exception.IPAddressInUse(ip=ip_addr)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def enable_cifs_service(nas_server, domain, username, password):
|
||||||
|
try:
|
||||||
|
nas_server.enable_cifs_service(
|
||||||
|
nas_server.file_interface,
|
||||||
|
domain=domain,
|
||||||
|
domain_username=username,
|
||||||
|
domain_password=password)
|
||||||
|
except storops_ex.UnitySmbNameInUseError:
|
||||||
|
LOG.info(_LI('CIFS service on NAS server %s is '
|
||||||
|
'already enabled.'), nas_server.name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def enable_nfs_service(nas_server):
|
||||||
|
try:
|
||||||
|
nas_server.enable_nfs_service()
|
||||||
|
except storops_ex.UnityNfsAlreadyEnabledError:
|
||||||
|
LOG.info(_LI('NFS service on NAS server %s is '
|
||||||
|
'already enabled.'), nas_server.name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_snapshot(filesystem, name):
|
||||||
|
access_type = enums.FilesystemSnapAccessTypeEnum.CHECKPOINT
|
||||||
|
try:
|
||||||
|
return filesystem.create_snap(name, fs_access_type=access_type)
|
||||||
|
except storops_ex.UnitySnapNameInUseError:
|
||||||
|
LOG.info(_LI('Snapshot %(snap)s on Filesystem %(fs)s already '
|
||||||
|
'exists.'), {'snap': name, 'fs': filesystem.name})
|
||||||
|
|
||||||
|
def create_snap_of_snap(self, src_snap, dst_snap_name, snap_type):
|
||||||
|
access_type = enums.FilesystemSnapAccessTypeEnum.PROTOCOL
|
||||||
|
if snap_type == 'checkpoint':
|
||||||
|
access_type = enums.FilesystemSnapAccessTypeEnum.CHECKPOINT
|
||||||
|
|
||||||
|
if isinstance(src_snap, six.string_types):
|
||||||
|
snap = self.get_snapshot(name=src_snap)
|
||||||
|
else:
|
||||||
|
snap = src_snap
|
||||||
|
|
||||||
|
try:
|
||||||
|
return snap.create_snap(dst_snap_name, fs_access_type=access_type)
|
||||||
|
except storops_ex.UnitySnapNameInUseError:
|
||||||
|
return self.get_snapshot(dst_snap_name)
|
||||||
|
|
||||||
|
def get_snapshot(self, name):
|
||||||
|
return self.system.get_snap(name=name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_snapshot(snap):
|
||||||
|
try:
|
||||||
|
snap.delete()
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
LOG.info(_LI('Snapshot %s is already removed.'), snap.name)
|
||||||
|
|
||||||
|
def get_pool(self, name=None):
|
||||||
|
return self.system.get_pool(name=name)
|
||||||
|
|
||||||
|
def get_storage_processor(self, sp_id):
|
||||||
|
sp = self.system.get_sp(sp_id)
|
||||||
|
return sp if sp.existed else None
|
||||||
|
|
||||||
|
def cifs_clear_access(self, share_name, white_list=None):
|
||||||
|
share = self.system.get_cifs_share(name=share_name)
|
||||||
|
share.clear_access(white_list)
|
||||||
|
|
||||||
|
def nfs_clear_access(self, share_name, white_list=None):
|
||||||
|
share = self.system.get_nfs_share(name=share_name)
|
||||||
|
share.clear_access(white_list, force_create_host=True)
|
||||||
|
|
||||||
|
def cifs_allow_access(self, share_name, user_name, access_level):
|
||||||
|
share = self.system.get_cifs_share(name=share_name)
|
||||||
|
|
||||||
|
if access_level == const.ACCESS_LEVEL_RW:
|
||||||
|
cifs_access = enums.ACEAccessLevelEnum.WRITE
|
||||||
|
else:
|
||||||
|
cifs_access = enums.ACEAccessLevelEnum.READ
|
||||||
|
|
||||||
|
share.add_ace(user=user_name, access_level=cifs_access)
|
||||||
|
|
||||||
|
def nfs_allow_access(self, share_name, host_ip, access_level):
|
||||||
|
share = self.system.get_nfs_share(name=share_name)
|
||||||
|
if access_level == const.ACCESS_LEVEL_RW:
|
||||||
|
share.allow_read_write_access(host_ip, force_create_host=True)
|
||||||
|
share.allow_root_access(host_ip, force_create_host=True)
|
||||||
|
else:
|
||||||
|
share.allow_read_only_access(host_ip, force_create_host=True)
|
||||||
|
|
||||||
|
def cifs_deny_access(self, share_name, user_name):
|
||||||
|
share = self.system.get_cifs_share(name=share_name)
|
||||||
|
|
||||||
|
share.delete_ace(user=user_name)
|
||||||
|
|
||||||
|
def nfs_deny_access(self, share_name, host_ip):
|
||||||
|
share = self.system.get_nfs_share(name=share_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
share.delete_access(host_ip)
|
||||||
|
except storops_ex.UnityHostNotFoundException:
|
||||||
|
LOG.info(_LI('%(host)s access to %(share)s is already removed.'),
|
||||||
|
{'host': host_ip, 'share': share_name})
|
||||||
|
|
||||||
|
def get_ip_ports(self, sp=None):
|
||||||
|
ports = self.system.get_ip_port()
|
||||||
|
link_up_ports = []
|
||||||
|
for port in ports:
|
||||||
|
if port.is_link_up and 'eth' in port.id:
|
||||||
|
if sp and port.sp.id != sp.id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
link_up_ports.append(port)
|
||||||
|
|
||||||
|
return link_up_ports
|
632
manila/share/drivers/emc/plugins/unity/connection.py
Normal file
632
manila/share/drivers/emc/plugins/unity/connection.py
Normal file
@ -0,0 +1,632 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
"""Unity backend for the EMC Manila driver."""
|
||||||
|
|
||||||
|
from oslo_log import log
|
||||||
|
from oslo_utils import excutils
|
||||||
|
from oslo_utils import importutils
|
||||||
|
from oslo_utils import units
|
||||||
|
|
||||||
|
storops = importutils.try_import('storops')
|
||||||
|
if storops:
|
||||||
|
from storops import exception as storops_ex
|
||||||
|
from storops.unity import enums
|
||||||
|
|
||||||
|
from manila.common import constants as const
|
||||||
|
from manila import exception
|
||||||
|
from manila.i18n import _, _LE, _LW, _LI
|
||||||
|
from manila.share.drivers.emc.plugins import base as driver
|
||||||
|
from manila.share.drivers.emc.plugins.unity import client
|
||||||
|
from manila.share.drivers.emc.plugins.unity import utils as unity_utils
|
||||||
|
from manila.share.drivers.emc.plugins.vnx import utils as emc_utils
|
||||||
|
from manila.share import utils as share_utils
|
||||||
|
from manila import utils
|
||||||
|
|
||||||
|
VERSION = "1.0.0"
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
SUPPORTED_NETWORK_TYPES = (None, 'flat', 'vlan')
|
||||||
|
|
||||||
|
|
||||||
|
@emc_utils.decorate_all_methods(emc_utils.log_enter_exit,
|
||||||
|
debug_only=True)
|
||||||
|
class UnityStorageConnection(driver.StorageConnection):
|
||||||
|
"""Implements Unity specific functionality for EMC Manila driver."""
|
||||||
|
|
||||||
|
IP_ALLOCATIONS = 2
|
||||||
|
|
||||||
|
@emc_utils.log_enter_exit
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(UnityStorageConnection, self).__init__(*args, **kwargs)
|
||||||
|
self.client = None
|
||||||
|
self.pool_set = None
|
||||||
|
self.port_set = None
|
||||||
|
self.nas_server_pool = None
|
||||||
|
self.storage_processor = None
|
||||||
|
self.reserved_percentage = None
|
||||||
|
self.max_over_subscription_ratio = None
|
||||||
|
|
||||||
|
# props from super class.
|
||||||
|
self.driver_handles_share_servers = True
|
||||||
|
|
||||||
|
def connect(self, emc_share_driver, context):
|
||||||
|
"""Connect to Unity storage."""
|
||||||
|
config = emc_share_driver.configuration
|
||||||
|
storage_ip = config.emc_nas_server
|
||||||
|
username = config.emc_nas_login
|
||||||
|
password = config.emc_nas_password
|
||||||
|
sp_name = config.emc_nas_server_container
|
||||||
|
self.client = client.UnityClient(storage_ip, username, password)
|
||||||
|
|
||||||
|
pool_conf = config.safe_get(
|
||||||
|
'emc_nas_pool_names')
|
||||||
|
self.pool_set = self._get_managed_pools(pool_conf)
|
||||||
|
|
||||||
|
self.reserved_percentage = config.safe_get(
|
||||||
|
'reserved_share_percentage')
|
||||||
|
if self.reserved_percentage is None:
|
||||||
|
self.reserved_percentage = 0
|
||||||
|
|
||||||
|
self.max_over_subscription_ratio = config.safe_get(
|
||||||
|
'max_over_subscription_ratio')
|
||||||
|
|
||||||
|
self._config_sp(sp_name)
|
||||||
|
|
||||||
|
port_conf = config.safe_get(
|
||||||
|
'emc_interface_ports')
|
||||||
|
self.port_set = self._get_managed_ports(
|
||||||
|
port_conf, self.storage_processor)
|
||||||
|
|
||||||
|
pool_name = config.emc_nas_server_pool
|
||||||
|
self._config_pool(pool_name)
|
||||||
|
|
||||||
|
def check_for_setup_error(self):
|
||||||
|
"""Check for setup error."""
|
||||||
|
|
||||||
|
def create_share(self, context, share, share_server=None):
|
||||||
|
"""Create a share and export it based on protocol used."""
|
||||||
|
share_name = share['id']
|
||||||
|
size = share['size'] * units.Gi
|
||||||
|
|
||||||
|
# Check share's protocol.
|
||||||
|
# Throw an exception immediately if it is an invalid protocol.
|
||||||
|
share_proto = share['share_proto'].upper()
|
||||||
|
proto_enum = self._get_proto_enum(share_proto)
|
||||||
|
|
||||||
|
# Get pool name from share host field
|
||||||
|
pool_name = self._get_pool_name_from_host(share['host'])
|
||||||
|
# Get share server name from share server
|
||||||
|
server_name = self._get_server_name(share_server)
|
||||||
|
|
||||||
|
pool = self.client.get_pool(pool_name)
|
||||||
|
try:
|
||||||
|
nas_server = self.client.get_nas_server(server_name)
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
message = (_LE("Failed to get NAS server %(server)s when "
|
||||||
|
"creating the share %(share)s.") %
|
||||||
|
{'server': server_name, 'share': share_name})
|
||||||
|
LOG.error(message)
|
||||||
|
raise exception.EMCUnityError(err=message)
|
||||||
|
|
||||||
|
filesystem = self.client.create_filesystem(
|
||||||
|
pool, nas_server, share_name, size, proto=proto_enum)
|
||||||
|
|
||||||
|
locations = None
|
||||||
|
if share_proto == 'CIFS':
|
||||||
|
self.client.create_cifs_share(filesystem, share_name)
|
||||||
|
|
||||||
|
locations = self._get_cifs_location(
|
||||||
|
nas_server.file_interface, share_name)
|
||||||
|
elif share_proto == 'NFS':
|
||||||
|
self.client.create_nfs_share(filesystem, share_name)
|
||||||
|
|
||||||
|
locations = self._get_nfs_location(
|
||||||
|
nas_server.file_interface, share_name)
|
||||||
|
|
||||||
|
return locations
|
||||||
|
|
||||||
|
def create_share_from_snapshot(self, context, share, snapshot,
|
||||||
|
share_server=None):
|
||||||
|
"""Create a share from a snapshot - clone a snapshot."""
|
||||||
|
share_name = share['id']
|
||||||
|
|
||||||
|
# Check share's protocol.
|
||||||
|
# Throw an exception immediately if it is an invalid protocol.
|
||||||
|
share_proto = share['share_proto'].upper()
|
||||||
|
self._validate_share_protocol(share_proto)
|
||||||
|
|
||||||
|
# Get share server name from share server
|
||||||
|
server_name = self._get_server_name(share_server)
|
||||||
|
|
||||||
|
try:
|
||||||
|
nas_server = self.client.get_nas_server(server_name)
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
message = (_LE("Failed to get NAS server %(server)s when "
|
||||||
|
"creating the share %(share)s.") %
|
||||||
|
{'server': server_name, 'share': share_name})
|
||||||
|
LOG.error(message)
|
||||||
|
raise exception.EMCUnityError(err=message)
|
||||||
|
|
||||||
|
backend_snap = self.client.create_snap_of_snap(snapshot['id'],
|
||||||
|
share_name,
|
||||||
|
snap_type='snapshot')
|
||||||
|
|
||||||
|
locations = None
|
||||||
|
if share_proto == 'CIFS':
|
||||||
|
self.client.create_cifs_share(backend_snap, share_name)
|
||||||
|
|
||||||
|
locations = self._get_cifs_location(
|
||||||
|
nas_server.file_interface, share_name)
|
||||||
|
elif share_proto == 'NFS':
|
||||||
|
self.client.create_nfs_share(backend_snap, share_name)
|
||||||
|
|
||||||
|
locations = self._get_nfs_location(
|
||||||
|
nas_server.file_interface, share_name)
|
||||||
|
|
||||||
|
return locations
|
||||||
|
|
||||||
|
def delete_share(self, context, share, share_server=None):
|
||||||
|
"""Delete a share."""
|
||||||
|
share_name = share['id']
|
||||||
|
try:
|
||||||
|
backend_share = self.client.get_share(share_name,
|
||||||
|
share['share_proto'])
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
LOG.warning(_LW("Share %s is not found when deleting the share"),
|
||||||
|
share_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Share created by the API create_share_from_snapshot()
|
||||||
|
if self._is_share_from_snapshot(backend_share):
|
||||||
|
filesystem = backend_share.snap.filesystem
|
||||||
|
self.client.delete_snapshot(backend_share.snap)
|
||||||
|
else:
|
||||||
|
filesystem = backend_share.filesystem
|
||||||
|
self.client.delete_share(backend_share)
|
||||||
|
|
||||||
|
if self._is_isolated_filesystem(filesystem):
|
||||||
|
self.client.delete_filesystem(filesystem)
|
||||||
|
|
||||||
|
def extend_share(self, share, new_size, share_server=None):
|
||||||
|
backend_share = self.client.get_share(share['id'],
|
||||||
|
share['share_proto'])
|
||||||
|
|
||||||
|
if not self._is_share_from_snapshot(backend_share):
|
||||||
|
backend_share.filesystem.extend(new_size * units.Gi)
|
||||||
|
else:
|
||||||
|
share_id = share['id']
|
||||||
|
reason = _LE("Driver does not support extending a "
|
||||||
|
"snapshot based share.")
|
||||||
|
raise exception.ShareExtendingError(share_id=share_id,
|
||||||
|
reason=reason)
|
||||||
|
|
||||||
|
def create_snapshot(self, context, snapshot, share_server=None):
|
||||||
|
"""Create snapshot from share."""
|
||||||
|
share_name = snapshot['share_id']
|
||||||
|
share_proto = snapshot['share']['share_proto']
|
||||||
|
backend_share = self.client.get_share(share_name, share_proto)
|
||||||
|
|
||||||
|
snapshot_name = snapshot['id']
|
||||||
|
if self._is_share_from_snapshot(backend_share):
|
||||||
|
self.client.create_snap_of_snap(backend_share.snap,
|
||||||
|
snapshot_name,
|
||||||
|
snap_type='checkpoint')
|
||||||
|
else:
|
||||||
|
self.client.create_snapshot(backend_share.filesystem,
|
||||||
|
snapshot_name)
|
||||||
|
|
||||||
|
def delete_snapshot(self, context, snapshot, share_server=None):
|
||||||
|
"""Delete a snapshot."""
|
||||||
|
snap = self.client.get_snapshot(snapshot['id'])
|
||||||
|
self.client.delete_snapshot(snap)
|
||||||
|
|
||||||
|
def update_access(self, context, share, access_rules, add_rules,
|
||||||
|
delete_rules, share_server=None):
|
||||||
|
# adding rules
|
||||||
|
if add_rules:
|
||||||
|
for rule in add_rules:
|
||||||
|
self.allow_access(context, share, rule, share_server)
|
||||||
|
|
||||||
|
# deleting rules
|
||||||
|
if delete_rules:
|
||||||
|
for rule in delete_rules:
|
||||||
|
self.deny_access(context, share, rule, share_server)
|
||||||
|
|
||||||
|
# recovery mode
|
||||||
|
if not (add_rules or delete_rules):
|
||||||
|
white_list = []
|
||||||
|
for rule in access_rules:
|
||||||
|
self.allow_access(context, share, rule, share_server)
|
||||||
|
white_list.append(rule['access_to'])
|
||||||
|
self.clear_access(share, white_list)
|
||||||
|
|
||||||
|
def clear_access(self, share, white_list=None):
|
||||||
|
share_proto = share['share_proto'].upper()
|
||||||
|
share_name = share['id']
|
||||||
|
if share_proto == 'CIFS':
|
||||||
|
self.client.cifs_clear_access(share_name, white_list)
|
||||||
|
elif share_proto == 'NFS':
|
||||||
|
self.client.nfs_clear_access(share_name, white_list)
|
||||||
|
|
||||||
|
def allow_access(self, context, share, access, share_server=None):
|
||||||
|
"""Allow access to a share."""
|
||||||
|
access_level = access['access_level']
|
||||||
|
if access_level not in const.ACCESS_LEVELS:
|
||||||
|
raise exception.InvalidShareAccessLevel(level=access_level)
|
||||||
|
|
||||||
|
share_proto = share['share_proto'].upper()
|
||||||
|
|
||||||
|
self._validate_share_protocol(share_proto)
|
||||||
|
self._validate_share_access_type(share, access)
|
||||||
|
|
||||||
|
if share_proto == 'CIFS':
|
||||||
|
self._cifs_allow_access(share, access)
|
||||||
|
elif share_proto == 'NFS':
|
||||||
|
self._nfs_allow_access(share, access)
|
||||||
|
|
||||||
|
def deny_access(self, context, share, access, share_server):
|
||||||
|
"""Deny access to a share."""
|
||||||
|
share_proto = share['share_proto'].upper()
|
||||||
|
|
||||||
|
self._validate_share_protocol(share_proto)
|
||||||
|
self._validate_share_access_type(share, access)
|
||||||
|
|
||||||
|
if share_proto == 'CIFS':
|
||||||
|
self._cifs_deny_access(share, access)
|
||||||
|
elif share_proto == 'NFS':
|
||||||
|
self._nfs_deny_access(share, access)
|
||||||
|
|
||||||
|
def ensure_share(self, context, share, share_server):
|
||||||
|
"""Ensure that the share is exported."""
|
||||||
|
share_name = share['id']
|
||||||
|
share_proto = share['share_proto']
|
||||||
|
|
||||||
|
backend_share = self.client.get_share(share_name, share_proto)
|
||||||
|
if not backend_share.existed:
|
||||||
|
raise exception.ShareNotFound(share_id=share_name)
|
||||||
|
|
||||||
|
def update_share_stats(self, stats_dict):
|
||||||
|
"""Communicate with EMCNASClient to get the stats."""
|
||||||
|
stats_dict['driver_version'] = VERSION
|
||||||
|
stats_dict['pools'] = []
|
||||||
|
|
||||||
|
for pool in self.client.get_pool():
|
||||||
|
if pool.name in self.pool_set:
|
||||||
|
# the unit of following numbers are GB
|
||||||
|
total_size = float(pool.size_total)
|
||||||
|
used_size = float(pool.size_used)
|
||||||
|
|
||||||
|
pool_stat = {
|
||||||
|
'pool_name': pool.name,
|
||||||
|
'thin_provisioning': True,
|
||||||
|
'total_capacity_gb': total_size,
|
||||||
|
'free_capacity_gb': total_size - used_size,
|
||||||
|
'allocated_capacity_gb': used_size,
|
||||||
|
'provisioned_capacity_gb': float(pool.size_subscribed),
|
||||||
|
'qos': False,
|
||||||
|
'reserved_percentage': self.reserved_percentage,
|
||||||
|
'max_over_subscription_ratio':
|
||||||
|
self.max_over_subscription_ratio,
|
||||||
|
}
|
||||||
|
stats_dict['pools'].append(pool_stat)
|
||||||
|
|
||||||
|
if not stats_dict.get('pools'):
|
||||||
|
message = _LE("Failed to update storage pool.")
|
||||||
|
LOG.error(message)
|
||||||
|
raise exception.EMCUnityError(err=message)
|
||||||
|
|
||||||
|
def get_pool(self, share):
|
||||||
|
"""Get the pool name of the share."""
|
||||||
|
backend_share = self.client.get_share(
|
||||||
|
share['id'], share['share_proto'])
|
||||||
|
|
||||||
|
return backend_share.filesystem.pool.name
|
||||||
|
|
||||||
|
def get_network_allocations_number(self):
|
||||||
|
"""Returns number of network allocations for creating VIFs."""
|
||||||
|
return self.IP_ALLOCATIONS
|
||||||
|
|
||||||
|
def setup_server(self, network_info, metadata=None):
|
||||||
|
"""Set up and configures share server with given network parameters."""
|
||||||
|
server_name = network_info['server_id']
|
||||||
|
nas_server = self.client.create_nas_server(server_name,
|
||||||
|
self.storage_processor,
|
||||||
|
self.nas_server_pool)
|
||||||
|
|
||||||
|
try:
|
||||||
|
for network in network_info['network_allocations']:
|
||||||
|
self._create_network_interface(nas_server, network)
|
||||||
|
|
||||||
|
self._handle_security_services(
|
||||||
|
nas_server, network_info['security_services'])
|
||||||
|
|
||||||
|
return {'share_server_name': server_name}
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
LOG.error(_LE('Could not setup server. Reason: %s.'), ex)
|
||||||
|
server_details = {'share_server_name': server_name}
|
||||||
|
self.teardown_server(
|
||||||
|
server_details, network_info['security_services'])
|
||||||
|
|
||||||
|
def teardown_server(self, server_details, security_services=None):
|
||||||
|
"""Teardown share server."""
|
||||||
|
if not server_details:
|
||||||
|
LOG.debug('Server details are empty.')
|
||||||
|
return
|
||||||
|
|
||||||
|
server_name = server_details.get('share_server_name')
|
||||||
|
if not server_name:
|
||||||
|
LOG.debug('No share server found for server %s.',
|
||||||
|
server_details.get('instance_id'))
|
||||||
|
return
|
||||||
|
|
||||||
|
username = None
|
||||||
|
password = None
|
||||||
|
for security_service in security_services:
|
||||||
|
if security_service['type'] == 'active_directory':
|
||||||
|
username = security_service['user']
|
||||||
|
password = security_service['password']
|
||||||
|
break
|
||||||
|
|
||||||
|
self.client.delete_nas_server(server_name, username, password)
|
||||||
|
|
||||||
|
def _cifs_allow_access(self, share, access):
|
||||||
|
"""Allow access to CIFS share."""
|
||||||
|
self.client.cifs_allow_access(
|
||||||
|
share['id'], access['access_to'], access['access_level'])
|
||||||
|
|
||||||
|
def _cifs_deny_access(self, share, access):
|
||||||
|
"""Deny access to CIFS share."""
|
||||||
|
self.client.cifs_deny_access(share['id'], access['access_to'])
|
||||||
|
|
||||||
|
def _config_pool(self, pool_name):
|
||||||
|
try:
|
||||||
|
self.nas_server_pool = self.client.get_pool(pool_name)
|
||||||
|
except storops_ex.UnityResourceNotFoundError:
|
||||||
|
message = (_LE("The storage pools %s to store NAS server "
|
||||||
|
"configuration do not exist.") % pool_name)
|
||||||
|
LOG.error(message)
|
||||||
|
raise exception.BadConfigurationException(reason=message)
|
||||||
|
|
||||||
|
def _config_sp(self, sp_name):
|
||||||
|
self.storage_processor = self.client.get_storage_processor(
|
||||||
|
sp_name.lower())
|
||||||
|
if self.storage_processor is None:
|
||||||
|
message = (_LE("The storage processor %s does not exist or "
|
||||||
|
"is unavailable. Please reconfigure it in "
|
||||||
|
"manila.conf.") % sp_name)
|
||||||
|
LOG.error(message)
|
||||||
|
raise exception.BadConfigurationException(reason=message)
|
||||||
|
|
||||||
|
def _create_network_interface(self, nas_server, network):
|
||||||
|
ip_addr = network['ip_address']
|
||||||
|
netmask = utils.cidr_to_netmask(network['cidr'])
|
||||||
|
gateway = network['gateway']
|
||||||
|
vlan_id = network['segmentation_id']
|
||||||
|
if network['network_type'] not in SUPPORTED_NETWORK_TYPES:
|
||||||
|
msg = _('The specified network type %s is unsupported by '
|
||||||
|
'the EMC Unity driver')
|
||||||
|
raise exception.NetworkBadConfigurationException(
|
||||||
|
reason=msg % network['network_type'])
|
||||||
|
|
||||||
|
# Create the interfaces on NAS server
|
||||||
|
self.client.create_interface(nas_server,
|
||||||
|
ip_addr,
|
||||||
|
netmask,
|
||||||
|
gateway,
|
||||||
|
ports=self.port_set,
|
||||||
|
vlan_id=vlan_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_cifs_location(file_interfaces, share_name):
|
||||||
|
return [
|
||||||
|
{'path': r'\\%(interface)s\%(share_name)s' % {
|
||||||
|
'interface': interface.ip_address,
|
||||||
|
'share_name': share_name}
|
||||||
|
}
|
||||||
|
for interface in file_interfaces
|
||||||
|
]
|
||||||
|
|
||||||
|
def _get_managed_pools(self, pool_conf):
|
||||||
|
# Get the real pools from the backend storage
|
||||||
|
real_pools = set([pool.name for pool in self.client.get_pool()])
|
||||||
|
|
||||||
|
if not pool_conf:
|
||||||
|
LOG.debug("No storage pool is specified, so all pools in storage "
|
||||||
|
"system will be managed.")
|
||||||
|
return real_pools
|
||||||
|
|
||||||
|
matched_pools, unmanaged_pools = unity_utils.do_match(real_pools,
|
||||||
|
pool_conf)
|
||||||
|
|
||||||
|
if not matched_pools:
|
||||||
|
msg = (_("All the specified storage pools to be managed "
|
||||||
|
"do not exist. Please check your configuration "
|
||||||
|
"emc_nas_pool_names in manila.conf. "
|
||||||
|
"The available pools in the backend are %s") %
|
||||||
|
",".join(real_pools))
|
||||||
|
raise exception.BadConfigurationException(reason=msg)
|
||||||
|
|
||||||
|
if unmanaged_pools:
|
||||||
|
LOG.info(_LI("The following specified storage pools "
|
||||||
|
"are not managed by the backend: "
|
||||||
|
"%(un_managed)s. This host will only manage "
|
||||||
|
"the storage pools: %(exist)s"),
|
||||||
|
{'un_managed': ",".join(unmanaged_pools),
|
||||||
|
'exist': ",".join(matched_pools)})
|
||||||
|
else:
|
||||||
|
LOG.debug("Storage pools: %s will be managed.",
|
||||||
|
",".join(matched_pools))
|
||||||
|
|
||||||
|
return matched_pools
|
||||||
|
|
||||||
|
def _get_managed_ports(self, port_conf, sp):
|
||||||
|
# Get the real ports from the backend storage
|
||||||
|
real_ports = set([port.id for port in self.client.get_ip_ports(sp)])
|
||||||
|
|
||||||
|
if not port_conf:
|
||||||
|
LOG.debug("No ports are specified, so all ports in storage "
|
||||||
|
"system will be managed.")
|
||||||
|
return real_ports
|
||||||
|
|
||||||
|
matched_ports, unmanaged_ports = unity_utils.do_match(real_ports,
|
||||||
|
port_conf)
|
||||||
|
|
||||||
|
if not matched_ports:
|
||||||
|
msg = (_("All the specified storage ports to be managed "
|
||||||
|
"do not exist. Please check your configuration "
|
||||||
|
"emc_interface_ports in manila.conf. "
|
||||||
|
"The available ports in the backend are %s") %
|
||||||
|
",".join(real_ports))
|
||||||
|
raise exception.BadConfigurationException(reason=msg)
|
||||||
|
|
||||||
|
if unmanaged_ports:
|
||||||
|
LOG.info(_LI("The following specified ports "
|
||||||
|
"are not managed by the backend: "
|
||||||
|
"%(un_managed)s. This host will only manage "
|
||||||
|
"the storage ports: %(exist)s"),
|
||||||
|
{'un_managed': ",".join(unmanaged_ports),
|
||||||
|
'exist': ",".join(matched_ports)})
|
||||||
|
else:
|
||||||
|
LOG.debug("Ports: %s will be managed.",
|
||||||
|
",".join(matched_ports))
|
||||||
|
|
||||||
|
return matched_ports
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_nfs_location(file_interfaces, share_name):
|
||||||
|
return [
|
||||||
|
{'path': '%(interface)s:/%(share_name)s' % {
|
||||||
|
'interface': interface.ip_address,
|
||||||
|
'share_name': share_name}
|
||||||
|
}
|
||||||
|
for interface in file_interfaces
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_pool_name_from_host(host):
|
||||||
|
pool_name = share_utils.extract_host(host, level='pool')
|
||||||
|
if not pool_name:
|
||||||
|
message = (_("Pool is not available in the share host %s.") %
|
||||||
|
host)
|
||||||
|
raise exception.InvalidHost(reason=message)
|
||||||
|
|
||||||
|
return pool_name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_proto_enum(share_proto):
|
||||||
|
share_proto = share_proto.upper()
|
||||||
|
UnityStorageConnection._validate_share_protocol(share_proto)
|
||||||
|
|
||||||
|
if share_proto == 'CIFS':
|
||||||
|
return enums.FSSupportedProtocolEnum.CIFS
|
||||||
|
elif share_proto == 'NFS':
|
||||||
|
return enums.FSSupportedProtocolEnum.NFS
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_server_name(share_server):
|
||||||
|
if not share_server:
|
||||||
|
msg = _('Share server not provided.')
|
||||||
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
|
server_name = share_server.get(
|
||||||
|
'backend_details', {}).get('share_server_name')
|
||||||
|
|
||||||
|
if server_name is None:
|
||||||
|
msg = (_LE("Name of the share server %s not found.")
|
||||||
|
% share_server['id'])
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
|
return server_name
|
||||||
|
|
||||||
|
def _handle_security_services(self, nas_server, security_services):
|
||||||
|
kerberos_enabled = False
|
||||||
|
# Support 'active_directory' and 'kerberos'
|
||||||
|
for security_service in security_services:
|
||||||
|
service_type = security_service['type']
|
||||||
|
if service_type == 'active_directory':
|
||||||
|
# Create DNS server for NAS server
|
||||||
|
domain = security_service['domain']
|
||||||
|
dns_ip = security_service['dns_ip']
|
||||||
|
self.client.create_dns_server(nas_server,
|
||||||
|
domain,
|
||||||
|
dns_ip)
|
||||||
|
|
||||||
|
# Enable CIFS service
|
||||||
|
username = security_service['user']
|
||||||
|
password = security_service['password']
|
||||||
|
self.client.enable_cifs_service(nas_server,
|
||||||
|
domain=domain,
|
||||||
|
username=username,
|
||||||
|
password=password)
|
||||||
|
elif service_type == 'kerberos':
|
||||||
|
# Enable NFS service with kerberos
|
||||||
|
kerberos_enabled = True
|
||||||
|
# TODO(jay.xu): enable nfs service with kerberos
|
||||||
|
LOG.warning(_LW('Kerberos is not supported by '
|
||||||
|
'EMC Unity manila driver plugin.'))
|
||||||
|
elif service_type == 'ldap':
|
||||||
|
LOG.warning(_LW('LDAP is not supported by '
|
||||||
|
'EMC Unity manila driver plugin.'))
|
||||||
|
else:
|
||||||
|
LOG.warning(_LW('Unknown security service type: %s.'),
|
||||||
|
service_type)
|
||||||
|
|
||||||
|
if not kerberos_enabled:
|
||||||
|
# Enable NFS service without kerberos
|
||||||
|
self.client.enable_nfs_service(nas_server)
|
||||||
|
|
||||||
|
def _nfs_allow_access(self, share, access):
|
||||||
|
"""Allow access to NFS share."""
|
||||||
|
self.client.nfs_allow_access(
|
||||||
|
share['id'], access['access_to'], access['access_level'])
|
||||||
|
|
||||||
|
def _nfs_deny_access(self, share, access):
|
||||||
|
"""Deny access to NFS share."""
|
||||||
|
self.client.nfs_deny_access(share['id'], access['access_to'])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_isolated_filesystem(filesystem):
|
||||||
|
filesystem.update()
|
||||||
|
return (
|
||||||
|
not filesystem.has_snap() and
|
||||||
|
not (filesystem.cifs_share or filesystem.nfs_share)
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_share_from_snapshot(share):
|
||||||
|
return True if share.snap else False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _validate_share_access_type(share, access):
|
||||||
|
reason = None
|
||||||
|
share_proto = share['share_proto'].upper()
|
||||||
|
|
||||||
|
if share_proto == 'CIFS' and access['access_type'] != 'user':
|
||||||
|
reason = _('Only user access type allowed for CIFS share.')
|
||||||
|
elif share_proto == 'NFS' and access['access_type'] != 'ip':
|
||||||
|
reason = _('Only IP access type allowed for NFS share.')
|
||||||
|
|
||||||
|
if reason:
|
||||||
|
raise exception.InvalidShareAccess(reason=reason)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _validate_share_protocol(share_proto):
|
||||||
|
if share_proto not in ('NFS', 'CIFS'):
|
||||||
|
raise exception.InvalidShare(
|
||||||
|
reason=(_('Invalid NAS protocol supplied: %s.') %
|
||||||
|
share_proto))
|
34
manila/share/drivers/emc/plugins/unity/utils.py
Normal file
34
manila/share/drivers/emc/plugins/unity/utils.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
""" Utility module for EMC Unity Manila Driver """
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
|
||||||
|
|
||||||
|
def do_match(full, matcher_list):
|
||||||
|
matched = set()
|
||||||
|
|
||||||
|
full = set([item.strip() for item in full])
|
||||||
|
if matcher_list is None:
|
||||||
|
# default to all
|
||||||
|
matcher_list = set('*')
|
||||||
|
else:
|
||||||
|
matcher_list = set([item.strip() for item in matcher_list])
|
||||||
|
|
||||||
|
for item in full:
|
||||||
|
for matcher in matcher_list:
|
||||||
|
if fnmatch.fnmatchcase(item, matcher):
|
||||||
|
matched.add(item)
|
||||||
|
return matched, full - matched
|
@ -459,7 +459,7 @@ class VNXStorageConnection(driver.StorageConnection):
|
|||||||
raise exception.EMCVnxXMLAPIError(err=message)
|
raise exception.EMCVnxXMLAPIError(err=message)
|
||||||
|
|
||||||
real_pools = set([item for item in backend_pools])
|
real_pools = set([item for item in backend_pools])
|
||||||
conf_pools = set([item.strip() for item in pools.split(",")])
|
conf_pools = set([item.strip() for item in pools])
|
||||||
matched_pools, unmatched_pools = vnx_utils.do_match_any(
|
matched_pools, unmatched_pools = vnx_utils.do_match_any(
|
||||||
real_pools, conf_pools)
|
real_pools, conf_pools)
|
||||||
|
|
||||||
|
20
manila/tests/share/drivers/emc/plugins/unity/__init__.py
Normal file
20
manila/tests/share/drivers/emc/plugins/unity/__init__.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.modules['storops'] = mock.Mock()
|
||||||
|
sys.modules['storops.unity'] = mock.Mock()
|
@ -0,0 +1,66 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
class UnityFakeException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityException(UnityFakeException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnitySmbShareNameExistedError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityFileSystemNameAlreadyExisted(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityNasServerNameUsedError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityNfsShareNameExistedError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnitySnapNameInUseError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityIpAddressUsedError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityResourceNotFoundError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityOneDnsPerNasServerError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnitySmbNameInUseError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityNfsAlreadyEnabledError(UnityException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnityHostNotFoundException(UnityException):
|
||||||
|
pass
|
235
manila/tests/share/drivers/emc/plugins/unity/mocked_manila.yaml
Normal file
235
manila/tests/share/drivers/emc/plugins/unity/mocked_manila.yaml
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
network_allocations:
|
||||||
|
_type: 'network_allocations'
|
||||||
|
_properties: &network_allocations_prop
|
||||||
|
- id: '04ac4c27-9cf7-4406-809c-13edc93e4849'
|
||||||
|
ip_address: 'fake_ip_addr_1'
|
||||||
|
cidr: '192.168.1.0/24'
|
||||||
|
segmentation_id: null
|
||||||
|
gateway: '192.168.1.1'
|
||||||
|
network_type: flat
|
||||||
|
- id: '0cf87de7-5c65-4036-8b6a-e8176c356958'
|
||||||
|
ip_address: 'fake_ip_addr_2'
|
||||||
|
cidr: '192.168.1.0/24'
|
||||||
|
segmentation_id: null
|
||||||
|
gateway: '192.168.1.1'
|
||||||
|
network_type: flat
|
||||||
|
|
||||||
|
network_allocations_vlan:
|
||||||
|
_type: 'network_allocations'
|
||||||
|
_properties: &network_allocations_vlan_prop
|
||||||
|
- id: '04ac4c27-9cf7-4406-809c-13edc93e4849'
|
||||||
|
ip_address: 'fake_ip_addr_1'
|
||||||
|
cidr: '192.168.1.0/24'
|
||||||
|
segmentation_id: 160
|
||||||
|
gateway: '192.168.1.1'
|
||||||
|
network_type: vlan
|
||||||
|
- id: '0cf87de7-5c65-4036-8b6a-e8176c356958'
|
||||||
|
ip_address: 'fake_ip_addr_2'
|
||||||
|
cidr: '192.168.1.0/24'
|
||||||
|
segmentation_id: 160
|
||||||
|
gateway: '192.168.1.1'
|
||||||
|
network_type: vlan
|
||||||
|
|
||||||
|
network_allocations_vxlan:
|
||||||
|
_type: 'network_allocations'
|
||||||
|
_properties: &network_allocations_vxlan_prop
|
||||||
|
- id: '04ac4c27-9cf7-4406-809c-13edc93e4849'
|
||||||
|
ip_address: 'fake_ip_addr_1'
|
||||||
|
cidr: '192.168.1.0/24'
|
||||||
|
segmentation_id: 123
|
||||||
|
gateway: '192.168.1.1'
|
||||||
|
network_type: vxlan
|
||||||
|
|
||||||
|
active_directory:
|
||||||
|
_type: 'security_service'
|
||||||
|
_properties: &active_directory_prop
|
||||||
|
type: 'active_directory'
|
||||||
|
domain: 'fake_domain_name'
|
||||||
|
dns_ip: 'fake_dns_ip'
|
||||||
|
user: 'fake_user'
|
||||||
|
password: 'fake_password'
|
||||||
|
|
||||||
|
kerberos:
|
||||||
|
_type: 'security_service'
|
||||||
|
_properties: &kerberos_prop
|
||||||
|
<<: *active_directory_prop
|
||||||
|
type: 'kerberos'
|
||||||
|
server: 'fake_server'
|
||||||
|
|
||||||
|
security_services:
|
||||||
|
_type: 'security_services'
|
||||||
|
_properties: &security_services_prop
|
||||||
|
services: [*active_directory_prop, *kerberos_prop]
|
||||||
|
|
||||||
|
|
||||||
|
network_info__flat:
|
||||||
|
_type: 'network_info'
|
||||||
|
_properties: &network_info_flat_prop
|
||||||
|
name: 'share_network'
|
||||||
|
neutron_subnet_id: 'a3f3eeac-0b16-4932-8c03-0a37003644ff'
|
||||||
|
network_type: 'flat'
|
||||||
|
neutron_net_id: 'e6c96730-2bcf-4ce3-86fa-7cb7740086cb'
|
||||||
|
ip_version: 4
|
||||||
|
id: '232d8218-2743-41d1-832b-4194626e691e'
|
||||||
|
network_allocations: *network_allocations_prop
|
||||||
|
server_id: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
security_services: []
|
||||||
|
|
||||||
|
network_info__vlan:
|
||||||
|
_type: 'network_info'
|
||||||
|
_properties: &network_info__vlan_prop
|
||||||
|
<<: *network_info_flat_prop
|
||||||
|
network_type: 'vlan'
|
||||||
|
network_allocations: *network_allocations_vlan_prop
|
||||||
|
|
||||||
|
network_info__vxlan:
|
||||||
|
_type: 'network_info'
|
||||||
|
_properties: &network_info__vxlan_prop
|
||||||
|
<<: *network_info_flat_prop
|
||||||
|
network_type: 'vxlan'
|
||||||
|
network_allocations: *network_allocations_vxlan_prop
|
||||||
|
|
||||||
|
network_info__active_directory:
|
||||||
|
_type: 'network_info'
|
||||||
|
_properties:
|
||||||
|
<<: *network_info__vlan_prop
|
||||||
|
security_services: [*active_directory_prop]
|
||||||
|
|
||||||
|
network_info__kerberos:
|
||||||
|
_type: 'network_info'
|
||||||
|
_properties:
|
||||||
|
<<: *network_info_flat_prop
|
||||||
|
security_services: [*kerberos_prop]
|
||||||
|
|
||||||
|
share_server:
|
||||||
|
_type: 'share_server'
|
||||||
|
_properties: &share_server_prop
|
||||||
|
status: 'active'
|
||||||
|
share_network: *network_info_flat_prop
|
||||||
|
share_network_id: '232d8218-2743-41d1-832b-4194626e691e'
|
||||||
|
host: 'openstack@VNX'
|
||||||
|
backend_details:
|
||||||
|
share_server_name: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
network_allocations: *network_allocations_prop
|
||||||
|
id: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
|
||||||
|
share_server__no_share_server_name:
|
||||||
|
_type: 'share_server'
|
||||||
|
_properties:
|
||||||
|
<<: *share_server_prop
|
||||||
|
backend_details:
|
||||||
|
share_server_name: None
|
||||||
|
id: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
|
||||||
|
server_detail:
|
||||||
|
_type: 'server_detail'
|
||||||
|
_properties: &server_detail_prop
|
||||||
|
share_server_name: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
|
||||||
|
cifs_share:
|
||||||
|
_type: 'share'
|
||||||
|
_properties: &cifs_share_prop
|
||||||
|
share_id: '708e753c-aacb-411f-9c8a-8b8175da4e73'
|
||||||
|
availability_zone_id: 'de628fb6-1c99-41f6-a06a-adb61ff693b5'
|
||||||
|
share_network_id: '232d8218-2743-41d1-832b-4194626e691e'
|
||||||
|
share_server_id: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
id: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
size: 1
|
||||||
|
user_id: '19bbda71b578471a93363653dcb4c61d'
|
||||||
|
status: 'creating'
|
||||||
|
share_type_id: '57679eab-3e67-4052-b180-62b609670e93'
|
||||||
|
host: 'openstack@VNX#Pool_2'
|
||||||
|
display_name: 'cifs_share'
|
||||||
|
share_proto: 'CIFS'
|
||||||
|
export_locations: []
|
||||||
|
is_public: False
|
||||||
|
|
||||||
|
nfs_share:
|
||||||
|
_type: 'share'
|
||||||
|
_properties: &nfs_share_prop
|
||||||
|
share_id: '12eb3777-7008-4721-8243-422507db8f9d'
|
||||||
|
availability_zone_id: 'de628fb6-1c99-41f6-a06a-adb61ff693b5'
|
||||||
|
share_network_id: '232d8218-2743-41d1-832b-4194626e691e'
|
||||||
|
share_server_id: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
id: 'cb532599-8dc6-4c3e-bb21-74ea54be566c'
|
||||||
|
size: 1
|
||||||
|
user_id: '19bbda71b578471a93363653dcb4c61d'
|
||||||
|
status: 'creating'
|
||||||
|
share_type_id: '57679eab-3e67-4052-b180-62b609670e93'
|
||||||
|
host: 'openstack@VNX#Pool_2'
|
||||||
|
display_name: 'nfs_share'
|
||||||
|
share_proto: 'NFS'
|
||||||
|
export_locations: []
|
||||||
|
is_public: False
|
||||||
|
|
||||||
|
invalid_share:
|
||||||
|
_type: 'share'
|
||||||
|
_properties: &invalid_share_prop
|
||||||
|
share_id: '12eb3777-7008-4721-8243-422507db8f9d'
|
||||||
|
availability_zone_id: 'de628fb6-1c99-41f6-a06a-adb61ff693b5'
|
||||||
|
share_network_id: '232d8218-2743-41d1-832b-4194626e691e'
|
||||||
|
share_server_id: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
id: 'cb532599-8dc6-4c3e-bb21-74ea54be566c'
|
||||||
|
size: 1
|
||||||
|
user_id: '19bbda71b578471a93363653dcb4c61d'
|
||||||
|
status: 'creating'
|
||||||
|
share_type_id: '57679eab-3e67-4052-b180-62b609670e93'
|
||||||
|
host: 'openstack@VNX#Pool_2'
|
||||||
|
display_name: 'nfs_share'
|
||||||
|
share_proto: 'fake_proto'
|
||||||
|
export_locations: []
|
||||||
|
is_public: False
|
||||||
|
|
||||||
|
snapshot:
|
||||||
|
_type: 'snapshot'
|
||||||
|
_properties: &snapshot_prop
|
||||||
|
status: 'creating'
|
||||||
|
share_instance_id: '27e4625e-c336-4749-85bc-634216755fbc'
|
||||||
|
share:
|
||||||
|
share_proto: 'CIFS'
|
||||||
|
snapshot_id: '345476cc-32ab-4565-ba88-e4733b7ffa0e'
|
||||||
|
progress: '0%'
|
||||||
|
id: 'ab411797-b1cf-4035-bf14-8771a7bf1805'
|
||||||
|
share_id: '27e4625e-c336-4749-85bc-634216755fbc'
|
||||||
|
|
||||||
|
cifs_rw_access:
|
||||||
|
_type: 'access'
|
||||||
|
_properties:
|
||||||
|
access_level: 'rw'
|
||||||
|
access_to: 'administrator'
|
||||||
|
access_type: 'user'
|
||||||
|
|
||||||
|
cifs_ro_access:
|
||||||
|
_type: 'access'
|
||||||
|
_properties:
|
||||||
|
access_level: 'ro'
|
||||||
|
access_to: 'administrator'
|
||||||
|
access_type: 'user'
|
||||||
|
|
||||||
|
nfs_rw_access:
|
||||||
|
_type: 'access'
|
||||||
|
_properties:
|
||||||
|
access_level: 'rw'
|
||||||
|
access_to: '192.168.1.1'
|
||||||
|
access_type: 'ip'
|
||||||
|
|
||||||
|
nfs_rw_access_cidr:
|
||||||
|
_type: 'access'
|
||||||
|
_properties:
|
||||||
|
access_level: 'rw'
|
||||||
|
access_to: '192.168.1.0/24'
|
||||||
|
access_type: 'ip'
|
||||||
|
|
||||||
|
nfs_ro_access:
|
||||||
|
_type: 'access'
|
||||||
|
_properties:
|
||||||
|
access_level: 'ro'
|
||||||
|
access_to: '192.168.1.1'
|
||||||
|
access_type: 'ip'
|
||||||
|
|
||||||
|
invalid_access:
|
||||||
|
_type: 'access'
|
||||||
|
_properties:
|
||||||
|
access_level: 'fake_access_level'
|
||||||
|
access_to: 'fake_access_to'
|
||||||
|
access_type: 'fake_type'
|
958
manila/tests/share/drivers/emc/plugins/unity/mocked_unity.yaml
Normal file
958
manila/tests/share/drivers/emc/plugins/unity/mocked_unity.yaml
Normal file
@ -0,0 +1,958 @@
|
|||||||
|
sp_a: &sp_a
|
||||||
|
_properties:
|
||||||
|
name: 'SPA'
|
||||||
|
id: 'SPA'
|
||||||
|
existed: true
|
||||||
|
|
||||||
|
sp_b: &sp_b
|
||||||
|
_properties:
|
||||||
|
name: 'SPB'
|
||||||
|
id: 'SPB'
|
||||||
|
existed: true
|
||||||
|
|
||||||
|
sp_c: &sp_invalid
|
||||||
|
_properties:
|
||||||
|
id: 'SPC'
|
||||||
|
existed: false
|
||||||
|
|
||||||
|
interface_1: &interface_1
|
||||||
|
_properties:
|
||||||
|
ip_address: 'fake_ip_addr_1'
|
||||||
|
|
||||||
|
interface_2: &interface_2
|
||||||
|
_properties:
|
||||||
|
ip_address: 'fake_ip_addr_2'
|
||||||
|
|
||||||
|
nas_server: &nas_server
|
||||||
|
_properties: &nas_server_prop
|
||||||
|
name: '78fd845f-8e7d-487f-bfde-051d83e78103'
|
||||||
|
file_interface: [*interface_1, *interface_2]
|
||||||
|
current_sp: *sp_a
|
||||||
|
|
||||||
|
filesystem_base: &filesystem_base
|
||||||
|
_properties: &filesystem_base_prop
|
||||||
|
name: 'fake_filesystem_name'
|
||||||
|
id: 'fake_filesystem_id'
|
||||||
|
size_total: 50000000000
|
||||||
|
is_thin_enabled: true
|
||||||
|
pool: null
|
||||||
|
nas_server: null
|
||||||
|
cifs_share: []
|
||||||
|
nfs_share: []
|
||||||
|
_methods:
|
||||||
|
has_snap: False
|
||||||
|
|
||||||
|
snap_base:
|
||||||
|
_properties: &snap_base_prop
|
||||||
|
name: 'fake_snap_name'
|
||||||
|
id: 'fake_snap_id'
|
||||||
|
size: 50000000000
|
||||||
|
filesystem: *filesystem_base
|
||||||
|
|
||||||
|
share_base:
|
||||||
|
_properties: &share_base_prop
|
||||||
|
name: 'fake_share_name'
|
||||||
|
id: 'fake_share_id'
|
||||||
|
filesystem: null
|
||||||
|
snap: null
|
||||||
|
|
||||||
|
cifs_share_base: &cifs_share_base
|
||||||
|
_properties: &cifs_share_base_prop
|
||||||
|
<<: *share_base_prop
|
||||||
|
|
||||||
|
nfs_share_base: &nfs_share_base
|
||||||
|
_properties: &nfs_share_base_prop
|
||||||
|
<<: *share_base_prop
|
||||||
|
|
||||||
|
pool_base:
|
||||||
|
_properties: &pool_base_prop
|
||||||
|
name: 'fake_pool_name'
|
||||||
|
pool_id: 0
|
||||||
|
state: Ready
|
||||||
|
user_capacity_gbs: 1311
|
||||||
|
total_subscribed_capacity_gbs: 131
|
||||||
|
available_capacity_gbs: 132
|
||||||
|
percent_full_threshold: 70
|
||||||
|
fast_cache: True
|
||||||
|
|
||||||
|
|
||||||
|
pool_1: &pool_1
|
||||||
|
_properties: &pool_1_prop
|
||||||
|
<<: *pool_base_prop
|
||||||
|
name: 'pool_1'
|
||||||
|
size_total: 500000
|
||||||
|
size_used: 10000
|
||||||
|
size_subscribed: 30000
|
||||||
|
|
||||||
|
pool_2: &pool_2
|
||||||
|
_properties: &pool_2_prop
|
||||||
|
<<: *pool_base_prop
|
||||||
|
name: 'pool_2'
|
||||||
|
size_total: 600000
|
||||||
|
size_used: 20000
|
||||||
|
size_subscribed: 40000
|
||||||
|
|
||||||
|
nas_server_pool: &nas_server_pool
|
||||||
|
_properties:
|
||||||
|
<<: *pool_base_prop
|
||||||
|
name: 'nas_server_pool'
|
||||||
|
|
||||||
|
port_base:
|
||||||
|
_properties: &port_base_prop
|
||||||
|
is_link_up: true
|
||||||
|
id: 'fake_name'
|
||||||
|
sp: *sp_a
|
||||||
|
|
||||||
|
port_1: &port_1
|
||||||
|
_properties:
|
||||||
|
<<: *port_base_prop
|
||||||
|
is_link_up: true
|
||||||
|
id: 'spa_eth1'
|
||||||
|
sp: *sp_a
|
||||||
|
|
||||||
|
port_2: &port_2
|
||||||
|
_properties:
|
||||||
|
<<: *port_base_prop
|
||||||
|
is_link_up: true
|
||||||
|
id: 'spa_eth2'
|
||||||
|
sp: *sp_a
|
||||||
|
|
||||||
|
port_3: &port_internal_port
|
||||||
|
_properties:
|
||||||
|
<<: *port_base_prop
|
||||||
|
is_link_up: true
|
||||||
|
id: 'internal_port'
|
||||||
|
sp: *sp_a
|
||||||
|
|
||||||
|
unity_base: &unity_base
|
||||||
|
_methods: &unity_base_method
|
||||||
|
get_sp: *sp_a
|
||||||
|
get_pool:
|
||||||
|
_side_effect: [[*pool_1, *pool_2, *nas_server_pool], *nas_server_pool]
|
||||||
|
get_ip_port: [*port_1, *port_2]
|
||||||
|
|
||||||
|
test_connect: &test_connect
|
||||||
|
unity: *unity_base
|
||||||
|
|
||||||
|
test_connect__invalid_sp_configuration:
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_sp: *sp_invalid
|
||||||
|
|
||||||
|
test_connect__invalid_pool_configuration: *test_connect
|
||||||
|
|
||||||
|
test_create_nfs_share:
|
||||||
|
nfs_share: &nfs_share__test_create_nfs_share
|
||||||
|
_properties:
|
||||||
|
<<: *nfs_share_base_prop
|
||||||
|
name: 'cb532599-8dc6-4c3e-bb21-74ea54be566c'
|
||||||
|
|
||||||
|
filesystem: &filesystem__test_create_nfs_share
|
||||||
|
_properties: &filesystem_prop__test_create_nfs_share
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd4587340'
|
||||||
|
_methods:
|
||||||
|
create_nfs_share: *nfs_share__test_create_nfs_share
|
||||||
|
|
||||||
|
pool: &pool__test_create_nfs_share
|
||||||
|
_properties:
|
||||||
|
<<: *pool_base_prop
|
||||||
|
name: 'Pool_2'
|
||||||
|
_methods:
|
||||||
|
create_filesystem: *filesystem__test_create_nfs_share
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_pool:
|
||||||
|
_side_effect: [[*pool_1, *pool_2, *nas_server_pool],
|
||||||
|
*nas_server_pool, *pool__test_create_nfs_share]
|
||||||
|
get_nas_server: *nas_server
|
||||||
|
|
||||||
|
test_create_cifs_share:
|
||||||
|
cifs_share: &cifs_share__test_create_cifs_share
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
enable_ace:
|
||||||
|
|
||||||
|
filesystem: &filesystem__test_create_cifs_share
|
||||||
|
_properties: &filesystem_prop__test_create_cifs_share
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd4587340'
|
||||||
|
_methods:
|
||||||
|
create_cifs_share: *cifs_share__test_create_cifs_share
|
||||||
|
|
||||||
|
pool: &pool__test_create_cifs_share
|
||||||
|
_properties:
|
||||||
|
<<: *pool_base_prop
|
||||||
|
name: 'Pool_2'
|
||||||
|
_methods:
|
||||||
|
create_filesystem: *filesystem__test_create_cifs_share
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_pool:
|
||||||
|
_side_effect: [[*pool_1, *pool_2, *nas_server_pool], *nas_server_pool,
|
||||||
|
*pool__test_create_cifs_share]
|
||||||
|
get_nas_server: *nas_server
|
||||||
|
|
||||||
|
test_create_share_with_invalid_share_server:
|
||||||
|
pool: &pool__test_create_share_with_invalid_share_server
|
||||||
|
_properties:
|
||||||
|
<<: *pool_base_prop
|
||||||
|
name: 'Pool_2'
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_pool:
|
||||||
|
_side_effect: [[*pool_1, *pool_2, *nas_server_pool], *nas_server_pool,
|
||||||
|
*pool__test_create_share_with_invalid_share_server]
|
||||||
|
get_nas_server:
|
||||||
|
_raise:
|
||||||
|
UnityResourceNotFoundError: 'Failed to get NAS server.'
|
||||||
|
|
||||||
|
|
||||||
|
test_delete_share:
|
||||||
|
filesystem: &filesystem__test_delete_share
|
||||||
|
_properties: &filesystem_prop__test_delete_share
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
update:
|
||||||
|
has_snap: False
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_delete_share
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_delete_share
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_delete_share
|
||||||
|
|
||||||
|
test_delete_share__with_invalid_share:
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share:
|
||||||
|
_raise:
|
||||||
|
UnityResourceNotFoundError: 'Failed to get CIFS share.'
|
||||||
|
|
||||||
|
test_delete_share__create_from_snap:
|
||||||
|
filesystem: &filesystem__test_delete_share__create_from_snap
|
||||||
|
_properties: &filesystem_prop__test_delete_share__create_from_snap
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd4587340'
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
update:
|
||||||
|
has_snap: False
|
||||||
|
|
||||||
|
snap: &snap__test_delete_share__create_from_snap
|
||||||
|
_properties: &snap_prop__test_delete_share__create_from_snap
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_delete_share__create_from_snap
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_delete_share__create_from_snap
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
snap: *snap__test_delete_share__create_from_snap
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_delete_share__create_from_snap
|
||||||
|
get_snap: *snap__test_delete_share__create_from_snap
|
||||||
|
|
||||||
|
test_delete_share__create_from_snap_but_not_isolated:
|
||||||
|
filesystem: &filesystem__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
_properties: &filesystem_prop__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd4587340'
|
||||||
|
cifs_share: [*cifs_share_base]
|
||||||
|
nfs_share: [*nfs_share_base]
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
update:
|
||||||
|
has_snap: True
|
||||||
|
|
||||||
|
snap: &snap__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
_properties: &snap_prop__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
snap: *snap__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_delete_share__create_from_snap_but_not_isolated
|
||||||
|
|
||||||
|
test_delete_share__but_not_isolated:
|
||||||
|
filesystem: &filesystem__test_delete_share__but_not_isolated
|
||||||
|
_properties: &filesystem_prop__test_delete_share__but_not_isolated
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd4587340'
|
||||||
|
_methods:
|
||||||
|
update:
|
||||||
|
has_snap: True
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_delete_share__but_not_isolated
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_delete_share__but_not_isolated
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_delete_share__but_not_isolated
|
||||||
|
|
||||||
|
test_extend_cifs_share:
|
||||||
|
filesystem: &filesystem__test_extend_cifs_share
|
||||||
|
_properties: &filesystem_prop__test_extend_cifs_share
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
extend:
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_extend_cifs_share
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_extend_cifs_share
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_extend_cifs_share
|
||||||
|
|
||||||
|
test_extend_nfs_share:
|
||||||
|
filesystem: &filesystem__test_extend_nfs_share
|
||||||
|
_properties: &filesystem_prop__test_extend_nfs_share
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
extend:
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_extend_nfs_share
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_extend_nfs_share
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nfs_share: *cifs_share__test_extend_nfs_share
|
||||||
|
|
||||||
|
test_extend_share__create_from_snap:
|
||||||
|
snap: &snap__test_extend_share__create_from_snap
|
||||||
|
_properties: &snap_prop__test_extend_share__create_from_snap
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_extend_share__create_from_snap
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
snap: *snap__test_extend_share__create_from_snap
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_extend_share__create_from_snap
|
||||||
|
|
||||||
|
test_create_snapshot_from_filesystem:
|
||||||
|
filesystem: &filesystem__test_create_snapshot_from_filesystem
|
||||||
|
_properties: &filesystem_prop__test_create_snapshot_from_filesystem
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
create_snap:
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_create_snapshot_from_filesystem
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_create_snapshot_from_filesystem
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_create_snapshot_from_filesystem
|
||||||
|
|
||||||
|
test_create_snapshot_from_snapshot:
|
||||||
|
snap: &snap__test_create_snapshot_from_snapshot
|
||||||
|
_properties: &snap_prop__test_create_snapshot_from_snapshot
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
create_snap:
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_create_snapshot_from_snapshot
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
snap: *snap__test_create_snapshot_from_snapshot
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_create_snapshot_from_snapshot
|
||||||
|
get_snap: *snap__test_create_snapshot_from_snapshot
|
||||||
|
|
||||||
|
test_delete_snapshot:
|
||||||
|
snap: &snap__test_delete_snapshot
|
||||||
|
_properties: &snap_prop__test_delete_snapshot
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_snap: *snap__test_delete_snapshot
|
||||||
|
|
||||||
|
test_ensure_share_exists:
|
||||||
|
cifs_share: &cifs_share_ensure_share_exists
|
||||||
|
_properties:
|
||||||
|
existed: True
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share_ensure_share_exists
|
||||||
|
|
||||||
|
test_ensure_share_not_exists:
|
||||||
|
cifs_share: &cifs_share_ensure_share_not_exists
|
||||||
|
_properties:
|
||||||
|
existed: False
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share_ensure_share_not_exists
|
||||||
|
|
||||||
|
test_update_share_stats:
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_pool:
|
||||||
|
_side_effect: [[*pool_1, *pool_2], *pool_1, [*pool_1, *pool_2]]
|
||||||
|
|
||||||
|
test_update_share_stats__nonexistent_pools:
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_pool:
|
||||||
|
_side_effect: [[*pool_1, *pool_2], *pool_1, []]
|
||||||
|
|
||||||
|
test_get_pool:
|
||||||
|
filesystem: &filesystem__test_get_pool
|
||||||
|
_properties: &filesystem_prop__test_get_pool
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
pool: *pool_1
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_get_pool
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
filesystem: *filesystem__test_get_pool
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_get_pool
|
||||||
|
|
||||||
|
test_setup_server: &test_setup_server
|
||||||
|
nas_server_1: &nas_server_1__test_setup_server
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
existed: false
|
||||||
|
|
||||||
|
nas_server_2: &nas_server_2__test_setup_server
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods: &nas_server_2__test_setup_server_mehtod
|
||||||
|
create_file_interface:
|
||||||
|
enable_nfs_service:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods: &unity_method__test_setup_server
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nas_server: *nas_server_1__test_setup_server
|
||||||
|
create_nas_server: *nas_server_2__test_setup_server
|
||||||
|
|
||||||
|
test_setup_server__vlan_network:
|
||||||
|
<<: *test_setup_server
|
||||||
|
nas_server: &nas_server__test_setup_server_flat_network
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
existed: true
|
||||||
|
_methods:
|
||||||
|
create_file_interface:
|
||||||
|
create_dns_server:
|
||||||
|
enable_nfs_service:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_method__test_setup_server
|
||||||
|
get_nas_server: *nas_server__test_setup_server_flat_network
|
||||||
|
|
||||||
|
test_setup_server__active_directory:
|
||||||
|
<<: *test_setup_server
|
||||||
|
nas_server_2: &nas_server_2__test_setup_server__active_directory
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods:
|
||||||
|
create_file_interface:
|
||||||
|
create_dns_server:
|
||||||
|
enable_cifs_service:
|
||||||
|
enable_nfs_service:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods: &unity_method__test_setup_server__active_directory
|
||||||
|
<<: *unity_method__test_setup_server
|
||||||
|
create_nas_server: *nas_server_2__test_setup_server__active_directory
|
||||||
|
|
||||||
|
test_setup_server__kerberos: *test_setup_server
|
||||||
|
|
||||||
|
test_setup_server__throw_exception:
|
||||||
|
<<: *test_setup_server
|
||||||
|
nas_server_1: &nas_server_1__test_setup_server__throw_exception
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
existed: false
|
||||||
|
|
||||||
|
nas_server_2: &nas_server_2__test_setup_server__throw_exception
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods:
|
||||||
|
create_file_interface:
|
||||||
|
create_dns_server:
|
||||||
|
enable_cifs_service:
|
||||||
|
enable_nfs_service:
|
||||||
|
_raise:
|
||||||
|
UnityException: 'Failed to enable NFS service.'
|
||||||
|
delete:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_method__test_setup_server
|
||||||
|
get_nas_server: *nas_server_2__test_setup_server__throw_exception
|
||||||
|
create_nas_server: *nas_server_2__test_setup_server__throw_exception
|
||||||
|
|
||||||
|
test_teardown_server:
|
||||||
|
nas_server: &nas_server__test_teardown_server
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nas_server: *nas_server__test_teardown_server
|
||||||
|
|
||||||
|
test__get_managed_pools: &test__get_managed_pools
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_pool: [*pool_1, *pool_2, *nas_server_pool]
|
||||||
|
|
||||||
|
test__get_managed_pools__invalid_pool_configuration: *test__get_managed_pools
|
||||||
|
|
||||||
|
test__get_managed_ports: &test__get_managed_ports
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_pool: [*pool_1, *pool_2, *nas_server_pool]
|
||||||
|
get_ip_port: [*port_1, *port_2, *port_internal_port]
|
||||||
|
|
||||||
|
test__get_managed_pools__invalid_port_configuration: *test__get_managed_ports
|
||||||
|
|
||||||
|
|
||||||
|
test_create_cifs_share_from_snapshot:
|
||||||
|
cifs_share: &cifs_share__test_create_cifs_share_from_snapshot
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
enable_ace:
|
||||||
|
|
||||||
|
snapshot_1: &snapshot_1__test_create_cifs_share_from_snapshot
|
||||||
|
_properties: &snapshot_1_prop__test_create_cifs_share_from_snapshot
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
create_cifs_share: *cifs_share__test_create_cifs_share_from_snapshot
|
||||||
|
|
||||||
|
snapshot_2: &snapshot_2__test_create_cifs_share_from_snapshot
|
||||||
|
_properties: &snapshot__prop__test_create_cifs_share_from_snapshot
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd4587340'
|
||||||
|
_methods:
|
||||||
|
create_snap: *snapshot_1__test_create_cifs_share_from_snapshot
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nas_server: *nas_server
|
||||||
|
get_snap: *snapshot_2__test_create_cifs_share_from_snapshot
|
||||||
|
|
||||||
|
test_create_nfs_share_from_snapshot:
|
||||||
|
nfs_share: &nfs_share__test_create_nfs_share_from_snapshot
|
||||||
|
_properties:
|
||||||
|
<<: *nfs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
enable_ace:
|
||||||
|
|
||||||
|
snapshot_1: &snapshot_1__test_create_nfs_share_from_snapshot
|
||||||
|
_properties: &snapshot_1_prop__test_create_nfs_share_from_snapshot
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
create_nfs_share: *nfs_share__test_create_nfs_share_from_snapshot
|
||||||
|
|
||||||
|
snapshot_2: &snapshot_2__test_create_nfs_share_from_snapshot
|
||||||
|
_properties: &snapshot__prop__test_create_nfs_share_from_snapshot
|
||||||
|
<<: *snap_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd4587340'
|
||||||
|
_methods:
|
||||||
|
create_snap: *snapshot_1__test_create_nfs_share_from_snapshot
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nas_server: *nas_server
|
||||||
|
get_snap: *snapshot_2__test_create_nfs_share_from_snapshot
|
||||||
|
|
||||||
|
test_create_share_from_snapshot_no_server_name:
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nas_server:
|
||||||
|
_raise:
|
||||||
|
UnityResourceNotFoundError: 'NAS server is not found'
|
||||||
|
|
||||||
|
test_clear_share_access_cifs:
|
||||||
|
cifs_share: &cifs_share__test_clear_share_access_cifs
|
||||||
|
_methods:
|
||||||
|
clear_access:
|
||||||
|
_raise:
|
||||||
|
UnityException: 'clear cifs access invoked'
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_clear_share_access_cifs
|
||||||
|
|
||||||
|
test_clear_share_access_nfs:
|
||||||
|
nfs_share: &nfs_share__test_clear_share_access_nfs
|
||||||
|
_methods:
|
||||||
|
clear_access:
|
||||||
|
_raise:
|
||||||
|
UnityException: 'clear nfs access invoked'
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nfs_share: *nfs_share__test_clear_share_access_nfs
|
||||||
|
|
||||||
|
test_allow_rw_cifs_share_access: &test_allow_rw_cifs_share_access
|
||||||
|
cifs_share: &cifs_share__test_allow_rw_cifs_share_access
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
add_ace:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_allow_rw_cifs_share_access
|
||||||
|
|
||||||
|
test_update_access_allow_rw: *test_allow_rw_cifs_share_access
|
||||||
|
|
||||||
|
test_update_access_recovery:
|
||||||
|
cifs_share: &cifs_share__test_update_access_recovery
|
||||||
|
_methods:
|
||||||
|
add_ace:
|
||||||
|
clear_access:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_update_access_recovery
|
||||||
|
|
||||||
|
test_allow_ro_cifs_share_access: *test_allow_rw_cifs_share_access
|
||||||
|
|
||||||
|
test_allow_rw_nfs_share_access:
|
||||||
|
nfs_share: &nfs_share__test_allow_rw_nfs_share_access
|
||||||
|
_properties:
|
||||||
|
<<: *nfs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
allow_read_write_access:
|
||||||
|
allow_root_access:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nfs_share: *nfs_share__test_allow_rw_nfs_share_access
|
||||||
|
|
||||||
|
test_allow_ro_nfs_share_access:
|
||||||
|
nfs_share: &nfs_share__test_allow_ro_nfs_share_access
|
||||||
|
_properties:
|
||||||
|
<<: *nfs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
allow_read_only_access:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nfs_share: *nfs_share__test_allow_ro_nfs_share_access
|
||||||
|
|
||||||
|
test_deny_cifs_share_access:
|
||||||
|
cifs_share: &cifs_share__test_deny_cifs_share_access
|
||||||
|
_properties:
|
||||||
|
<<: *cifs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
delete_ace:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_cifs_share: *cifs_share__test_deny_cifs_share_access
|
||||||
|
|
||||||
|
test_deny_nfs_share_access: &test_deny_nfs_share_access
|
||||||
|
nfs_share: &nfs_share__test_deny_nfs_share_access
|
||||||
|
_properties:
|
||||||
|
<<: *nfs_share_base_prop
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
_methods:
|
||||||
|
delete_access:
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
<<: *unity_base_method
|
||||||
|
get_nfs_share: *nfs_share__test_deny_nfs_share_access
|
||||||
|
|
||||||
|
test_update_access_deny_nfs: *test_deny_nfs_share_access
|
||||||
|
|
||||||
|
# The following test cases are for client.py
|
||||||
|
|
||||||
|
test_create_cifs_share__existed_expt:
|
||||||
|
filesystem:
|
||||||
|
_methods:
|
||||||
|
create_cifs_share:
|
||||||
|
_raise:
|
||||||
|
UnitySmbShareNameExistedError: 'CIFS share already exists.'
|
||||||
|
|
||||||
|
cifs_share: &cifs_share__test_create_cifs_share__existed_expt
|
||||||
|
_properties:
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
get_cifs_share: *cifs_share__test_create_cifs_share__existed_expt
|
||||||
|
|
||||||
|
test_create_nfs_share__existed_expt:
|
||||||
|
filesystem:
|
||||||
|
_methods:
|
||||||
|
create_nfs_share:
|
||||||
|
_raise:
|
||||||
|
UnityNfsShareNameExistedError: 'NFS share already exists.'
|
||||||
|
|
||||||
|
nfs_share: &nfs_share__test_create_nfs_share__existed_expt
|
||||||
|
_properties:
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
get_nfs_share: *nfs_share__test_create_nfs_share__existed_expt
|
||||||
|
|
||||||
|
test_get_share_with_invalid_proto:
|
||||||
|
share:
|
||||||
|
_properties:
|
||||||
|
<<: *share_base_prop
|
||||||
|
|
||||||
|
test_create_filesystem__existed_expt:
|
||||||
|
filesystem: &filesystem__test_create_filesystem__existed_expt
|
||||||
|
_properties:
|
||||||
|
name: '716100cc-e0b4-416b-ac27-d38dd019330d'
|
||||||
|
size: 10
|
||||||
|
proto: 'CIFS'
|
||||||
|
|
||||||
|
pool:
|
||||||
|
_methods:
|
||||||
|
create_filesystem:
|
||||||
|
_raise:
|
||||||
|
UnityFileSystemNameAlreadyExisted: 'Pool already exists.'
|
||||||
|
|
||||||
|
nas_server:
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
get_filesystem: *filesystem__test_create_filesystem__existed_expt
|
||||||
|
|
||||||
|
test_delete_filesystem__nonexistent_expt:
|
||||||
|
filesystem:
|
||||||
|
_properties:
|
||||||
|
name: already removed filsystem
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
_raise:
|
||||||
|
UnityResourceNotFoundError: 'Filesystem is non-existent.'
|
||||||
|
|
||||||
|
test_create_nas_server__existed_expt:
|
||||||
|
sp:
|
||||||
|
_properites:
|
||||||
|
name: 'SP'
|
||||||
|
|
||||||
|
pool:
|
||||||
|
_properites:
|
||||||
|
name: 'fake_pool'
|
||||||
|
|
||||||
|
nas_server: &nas_server__test_create_nas_server__existed_expt
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
create_nas_server:
|
||||||
|
_raise:
|
||||||
|
UnityNasServerNameUsedError: 'NAS Server already exists.'
|
||||||
|
get_nas_server: *nas_server__test_create_nas_server__existed_expt
|
||||||
|
|
||||||
|
test_delete_nas_server__nonexistent_expt:
|
||||||
|
nas_server: &nas_server__test_delete_nas_server__nonexistent_expt
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
_raise:
|
||||||
|
UnityResourceNotFoundError: 'NAS server is non-existent.'
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
get_nas_server: *nas_server__test_delete_nas_server__nonexistent_expt
|
||||||
|
|
||||||
|
test_create_dns_server__existed_expt:
|
||||||
|
nas_server:
|
||||||
|
_methods:
|
||||||
|
create_dns_server:
|
||||||
|
_raise:
|
||||||
|
UnityOneDnsPerNasServerError: 'DNS server already exists.'
|
||||||
|
|
||||||
|
test_create_interface__existed_expt:
|
||||||
|
nas_server:
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods:
|
||||||
|
create_file_interface:
|
||||||
|
_raise:
|
||||||
|
UnityIpAddressUsedError: 'IP address is already used.'
|
||||||
|
|
||||||
|
test_enable_cifs_service__existed_expt:
|
||||||
|
nas_server:
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods:
|
||||||
|
enable_cifs_service:
|
||||||
|
_raise:
|
||||||
|
UnitySmbNameInUseError: 'CIFS server already exists.'
|
||||||
|
|
||||||
|
test_enable_nfs_service__existed_expt:
|
||||||
|
nas_server:
|
||||||
|
_properties:
|
||||||
|
<<: *nas_server_prop
|
||||||
|
_methods:
|
||||||
|
enable_nfs_service:
|
||||||
|
_raise:
|
||||||
|
UnityNfsAlreadyEnabledError: 'NFS server already exists.'
|
||||||
|
|
||||||
|
test_create_snapshot__existed_expt:
|
||||||
|
filesystem:
|
||||||
|
_properties:
|
||||||
|
<<: *filesystem_base_prop
|
||||||
|
_methods:
|
||||||
|
create_snap:
|
||||||
|
_raise:
|
||||||
|
UnitySnapNameInUseError: 'Snapshot already exists.'
|
||||||
|
|
||||||
|
snapshot:
|
||||||
|
_properties:
|
||||||
|
<<: *snap_base_prop
|
||||||
|
|
||||||
|
test_create_snap_of_snap__existed_expt:
|
||||||
|
src_snapshot:
|
||||||
|
_methods:
|
||||||
|
create_snap:
|
||||||
|
_raise:
|
||||||
|
UnitySnapNameInUseError: 'Snapshot already exists.'
|
||||||
|
|
||||||
|
dest_snapshot: &dest_snapshot__test_create_snap_of_snap__existed_expt
|
||||||
|
_properties:
|
||||||
|
<<: *snap_base_prop
|
||||||
|
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
get_snap: *dest_snapshot__test_create_snap_of_snap__existed_expt
|
||||||
|
|
||||||
|
test_delete_snapshot__nonexistent_expt:
|
||||||
|
snapshot:
|
||||||
|
_properties:
|
||||||
|
<<: *snap_base_prop
|
||||||
|
_methods:
|
||||||
|
delete:
|
||||||
|
_raise:
|
||||||
|
UnityResourceNotFoundError: 'Snapshot is non-existent.'
|
||||||
|
|
||||||
|
test_nfs_deny_access__nonexistent_expt:
|
||||||
|
nfs_share: &nfs_share__test_nfs_deny_access__nonexistent_expt
|
||||||
|
_methods:
|
||||||
|
delete_access:
|
||||||
|
_raise:
|
||||||
|
UnityHostNotFoundException: "Unity Host is non-existent"
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
get_nfs_share: *nfs_share__test_nfs_deny_access__nonexistent_expt
|
||||||
|
|
||||||
|
test_get_storage_processor:
|
||||||
|
unity:
|
||||||
|
_methods:
|
||||||
|
get_sp: *sp_a
|
337
manila/tests/share/drivers/emc/plugins/unity/res_mock.py
Normal file
337
manila/tests/share/drivers/emc/plugins/unity/res_mock.py
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
from manila.share import configuration as conf
|
||||||
|
from manila.share.drivers.emc.plugins.unity import client
|
||||||
|
from manila.share.drivers.emc.plugins.unity import connection
|
||||||
|
from manila.tests.db import fakes as db_fakes
|
||||||
|
from manila.tests import fake_share
|
||||||
|
from manila.tests.share.drivers.emc.plugins.unity import fake_exceptions
|
||||||
|
from manila.tests.share.drivers.emc.plugins.unity import utils
|
||||||
|
|
||||||
|
client.storops_ex = fake_exceptions
|
||||||
|
connection.storops_ex = fake_exceptions
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
SYMBOL_TYPE = '_type'
|
||||||
|
SYMBOL_PROPERTIES = '_properties'
|
||||||
|
SYMBOL_METHODS = '_methods'
|
||||||
|
SYMBOL_SIDE_EFFECT = '_side_effect'
|
||||||
|
SYMBOL_RAISE = '_raise'
|
||||||
|
|
||||||
|
|
||||||
|
def _has_side_effect(node):
|
||||||
|
return isinstance(node, dict) and SYMBOL_SIDE_EFFECT in node
|
||||||
|
|
||||||
|
|
||||||
|
def _has_raise(node):
|
||||||
|
return isinstance(node, dict) and SYMBOL_RAISE in node
|
||||||
|
|
||||||
|
|
||||||
|
def fake_share_server(**kwargs):
|
||||||
|
share_server = {
|
||||||
|
'instance_id': 'fake_instance_id',
|
||||||
|
'backend_details': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
share_server.update(kwargs)
|
||||||
|
|
||||||
|
return db_fakes.FakeModel(share_server)
|
||||||
|
|
||||||
|
|
||||||
|
def fake_network_info(**kwargs):
|
||||||
|
network_info = {
|
||||||
|
'id': 'fake_net_id',
|
||||||
|
'name': 'net_name',
|
||||||
|
'subnet': [],
|
||||||
|
}
|
||||||
|
network_info.update(kwargs)
|
||||||
|
return network_info
|
||||||
|
|
||||||
|
|
||||||
|
def fake_server_detail(**kwargs):
|
||||||
|
server_detail = {
|
||||||
|
'share_server_name': 'fake_server_name',
|
||||||
|
}
|
||||||
|
server_detail.update(kwargs)
|
||||||
|
return server_detail
|
||||||
|
|
||||||
|
|
||||||
|
def fake_security_services(**kwargs):
|
||||||
|
return kwargs['services']
|
||||||
|
|
||||||
|
|
||||||
|
def fake_access(**kwargs):
|
||||||
|
access = {}
|
||||||
|
access.update(kwargs)
|
||||||
|
return access
|
||||||
|
|
||||||
|
|
||||||
|
class FakeEMCShareDriver(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.configuration = conf.Configuration(None)
|
||||||
|
self.configuration.emc_share_backend = 'unity'
|
||||||
|
self.configuration.emc_nas_server_container = 'SPA'
|
||||||
|
self.configuration.emc_nas_server = '192.168.1.1'
|
||||||
|
self.configuration.emc_nas_login = 'fake_user'
|
||||||
|
self.configuration.emc_nas_password = 'fake_password'
|
||||||
|
self.configuration.share_backend_name = 'EMC_NAS_Storage'
|
||||||
|
self.configuration.emc_nas_server_pool = 'nas_server_pool'
|
||||||
|
self.configuration.local_conf.max_over_subscription_ratio = 20
|
||||||
|
|
||||||
|
|
||||||
|
STATS = dict(
|
||||||
|
share_backend_name='Unity',
|
||||||
|
vendor_name='EMC',
|
||||||
|
storage_protocol='NFS_CIFS',
|
||||||
|
driver_version='2.0.0,',
|
||||||
|
pools=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DriverResourceMock(dict):
|
||||||
|
fake_func_mapping = {}
|
||||||
|
|
||||||
|
def __init__(self, yaml_file):
|
||||||
|
yaml_dict = utils.load_yaml(yaml_file)
|
||||||
|
if isinstance(yaml_dict, dict):
|
||||||
|
for name, body in yaml_dict.items():
|
||||||
|
if isinstance(body, dict):
|
||||||
|
props = body[SYMBOL_PROPERTIES]
|
||||||
|
if isinstance(props, dict):
|
||||||
|
for prop_name, prop_value in props.items():
|
||||||
|
if isinstance(prop_value, dict) and prop_value:
|
||||||
|
# get the first key as the convert function
|
||||||
|
func_name = list(prop_value.keys())[0]
|
||||||
|
if func_name.startswith('_'):
|
||||||
|
func = getattr(self, func_name)
|
||||||
|
props[prop_name] = (
|
||||||
|
func(**prop_value[func_name]))
|
||||||
|
if body[SYMBOL_TYPE] in self.fake_func_mapping:
|
||||||
|
self[name] = (
|
||||||
|
self.fake_func_mapping[body[SYMBOL_TYPE]](**props))
|
||||||
|
|
||||||
|
|
||||||
|
class ManilaResourceMock(DriverResourceMock):
|
||||||
|
fake_func_mapping = {
|
||||||
|
'share': fake_share.fake_share,
|
||||||
|
'snapshot': fake_share.fake_snapshot,
|
||||||
|
'network_info': fake_network_info,
|
||||||
|
'share_server': fake_share_server,
|
||||||
|
'server_detail': fake_server_detail,
|
||||||
|
'security_services': fake_security_services,
|
||||||
|
'access': fake_access,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, yaml_file):
|
||||||
|
super(ManilaResourceMock, self).__init__(yaml_file)
|
||||||
|
|
||||||
|
|
||||||
|
class StorageObjectMock(object):
|
||||||
|
PROPS = 'props'
|
||||||
|
|
||||||
|
def __init__(self, yaml_dict):
|
||||||
|
self.__dict__[StorageObjectMock.PROPS] = {}
|
||||||
|
props = yaml_dict.get(SYMBOL_PROPERTIES, None)
|
||||||
|
if props:
|
||||||
|
for k, v in props.items():
|
||||||
|
setattr(self, k, StoragePropertyMock(k, v)())
|
||||||
|
|
||||||
|
methods = yaml_dict.get(SYMBOL_METHODS, None)
|
||||||
|
if methods:
|
||||||
|
for k, v in methods.items():
|
||||||
|
setattr(self, k, StorageMethodMock(k, v))
|
||||||
|
|
||||||
|
def __setattr__(self, key, value):
|
||||||
|
self.__dict__[StorageObjectMock.PROPS][key] = value
|
||||||
|
|
||||||
|
def __getattr__(self, item):
|
||||||
|
try:
|
||||||
|
super(StorageObjectMock, self).__getattr__(item)
|
||||||
|
except AttributeError:
|
||||||
|
return self.__dict__[StorageObjectMock.PROPS][item]
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError('No such method or property for mock object.')
|
||||||
|
|
||||||
|
|
||||||
|
class StoragePropertyMock(mock.PropertyMock):
|
||||||
|
def __init__(self, name, property_body):
|
||||||
|
return_value = property_body
|
||||||
|
side_effect = None
|
||||||
|
|
||||||
|
# only support return_value and side_effect for property
|
||||||
|
if _has_side_effect(property_body):
|
||||||
|
side_effect = property_body[SYMBOL_SIDE_EFFECT]
|
||||||
|
return_value = None
|
||||||
|
|
||||||
|
if side_effect:
|
||||||
|
super(StoragePropertyMock, self).__init__(
|
||||||
|
name=name,
|
||||||
|
side_effect=side_effect)
|
||||||
|
elif return_value:
|
||||||
|
super(StoragePropertyMock, self).__init__(
|
||||||
|
name=name,
|
||||||
|
return_value=_build_mock_object(return_value))
|
||||||
|
else:
|
||||||
|
super(StoragePropertyMock, self).__init__(
|
||||||
|
name=name,
|
||||||
|
return_value=return_value)
|
||||||
|
|
||||||
|
|
||||||
|
class StorageMethodMock(mock.Mock):
|
||||||
|
def __init__(self, name, method_body):
|
||||||
|
return_value = method_body
|
||||||
|
exception = None
|
||||||
|
side_effect = None
|
||||||
|
|
||||||
|
# support return_value, side_effect and exception for method
|
||||||
|
if _has_side_effect(method_body) or _has_raise(method_body):
|
||||||
|
exception = method_body.get(SYMBOL_RAISE, None)
|
||||||
|
side_effect = method_body.get(SYMBOL_SIDE_EFFECT, None)
|
||||||
|
return_value = None
|
||||||
|
|
||||||
|
if exception:
|
||||||
|
if isinstance(exception, dict) and exception:
|
||||||
|
ex_name = list(exception.keys())[0]
|
||||||
|
ex = getattr(fake_exceptions, ex_name)
|
||||||
|
super(StorageMethodMock, self).__init__(
|
||||||
|
name=name,
|
||||||
|
side_effect=ex(exception[ex_name]))
|
||||||
|
elif side_effect:
|
||||||
|
super(StorageMethodMock, self).__init__(
|
||||||
|
name=name,
|
||||||
|
side_effect=_build_mock_object(side_effect))
|
||||||
|
elif return_value:
|
||||||
|
super(StorageMethodMock, self).__init__(
|
||||||
|
name=name,
|
||||||
|
return_value=_build_mock_object(return_value))
|
||||||
|
else:
|
||||||
|
super(StorageMethodMock, self).__init__(
|
||||||
|
name=name, return_value=None)
|
||||||
|
|
||||||
|
|
||||||
|
class StorageResourceMock(dict):
|
||||||
|
def __init__(self, yaml_file):
|
||||||
|
yaml_dict = utils.load_yaml(yaml_file)
|
||||||
|
if isinstance(yaml_dict, dict):
|
||||||
|
for section, sec_body in yaml_dict.items():
|
||||||
|
self[section] = {}
|
||||||
|
if isinstance(sec_body, dict):
|
||||||
|
for obj_name, obj_body in sec_body.items():
|
||||||
|
self[section][obj_name] = _build_mock_object(obj_body)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_mock_object(yaml_info):
|
||||||
|
return (isinstance(yaml_info, dict) and
|
||||||
|
(SYMBOL_PROPERTIES in yaml_info or SYMBOL_METHODS in yaml_info))
|
||||||
|
|
||||||
|
|
||||||
|
def _build_mock_object(yaml_dict):
|
||||||
|
if _is_mock_object(yaml_dict):
|
||||||
|
return StorageObjectMock(yaml_dict)
|
||||||
|
elif isinstance(yaml_dict, dict):
|
||||||
|
return {k: _build_mock_object(v) for k, v in yaml_dict.items()}
|
||||||
|
elif isinstance(yaml_dict, list):
|
||||||
|
return [_build_mock_object(each) for each in yaml_dict]
|
||||||
|
else:
|
||||||
|
return yaml_dict
|
||||||
|
|
||||||
|
|
||||||
|
manila_res = ManilaResourceMock('mocked_manila.yaml')
|
||||||
|
unity_res = StorageResourceMock('mocked_unity.yaml')
|
||||||
|
STORAGE_RES_MAPPING = {
|
||||||
|
'TestClient': unity_res,
|
||||||
|
'TestConnection': unity_res,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def mock_input(resource):
|
||||||
|
def inner_dec(func):
|
||||||
|
def decorated(cls, *args, **kwargs):
|
||||||
|
if cls._testMethodName in resource:
|
||||||
|
storage_res = resource[cls._testMethodName]
|
||||||
|
return func(cls, storage_res, *args, **kwargs)
|
||||||
|
|
||||||
|
return decorated
|
||||||
|
|
||||||
|
return inner_dec
|
||||||
|
|
||||||
|
|
||||||
|
mock_client_input = mock_input(unity_res)
|
||||||
|
|
||||||
|
|
||||||
|
def patch_client(func):
|
||||||
|
def client_decorator(cls, *args, **kwargs):
|
||||||
|
storage_res = {}
|
||||||
|
if func.__name__ in STORAGE_RES_MAPPING[cls.__class__.__name__]:
|
||||||
|
storage_res = (
|
||||||
|
STORAGE_RES_MAPPING[cls.__class__.__name__][func.__name__])
|
||||||
|
with utils.patch_system as patched_system:
|
||||||
|
if 'unity' in storage_res:
|
||||||
|
patched_system.return_value = storage_res['unity']
|
||||||
|
_client = client.UnityClient(host='fake_host',
|
||||||
|
username='fake_user',
|
||||||
|
password='fake_passwd')
|
||||||
|
return func(cls, _client, *args, **kwargs)
|
||||||
|
|
||||||
|
return client_decorator
|
||||||
|
|
||||||
|
|
||||||
|
def mock_driver_input(resource):
|
||||||
|
def inner_dec(func):
|
||||||
|
def decorated(cls, *args, **kwargs):
|
||||||
|
return func(cls, resource, *args, **kwargs)
|
||||||
|
|
||||||
|
return decorated
|
||||||
|
|
||||||
|
return inner_dec
|
||||||
|
|
||||||
|
|
||||||
|
mock_manila_input = mock_driver_input(manila_res)
|
||||||
|
|
||||||
|
|
||||||
|
def patch_connection_init(func):
|
||||||
|
def connection_decorator(cls, *args, **kwargs):
|
||||||
|
storage_res = {}
|
||||||
|
if func.__name__ in STORAGE_RES_MAPPING[cls.__class__.__name__]:
|
||||||
|
storage_res = (
|
||||||
|
STORAGE_RES_MAPPING[cls.__class__.__name__][func.__name__])
|
||||||
|
with utils.patch_system as patched_system:
|
||||||
|
if 'unity' in storage_res:
|
||||||
|
patched_system.return_value = storage_res['unity']
|
||||||
|
conn = connection.UnityStorageConnection(LOG)
|
||||||
|
return func(cls, conn, *args, **kwargs)
|
||||||
|
|
||||||
|
return connection_decorator
|
||||||
|
|
||||||
|
|
||||||
|
def patch_connection(func):
|
||||||
|
def connection_decorator(cls, *args, **kwargs):
|
||||||
|
storage_res = {}
|
||||||
|
if func.__name__ in STORAGE_RES_MAPPING[cls.__class__.__name__]:
|
||||||
|
storage_res = (
|
||||||
|
STORAGE_RES_MAPPING[cls.__class__.__name__][func.__name__])
|
||||||
|
with utils.patch_system as patched_system:
|
||||||
|
if 'unity' in storage_res:
|
||||||
|
patched_system.return_value = storage_res['unity']
|
||||||
|
conn = connection.UnityStorageConnection(LOG)
|
||||||
|
conn.connect(FakeEMCShareDriver(), None)
|
||||||
|
return func(cls, conn, *args, **kwargs)
|
||||||
|
|
||||||
|
return connection_decorator
|
158
manila/tests/share/drivers/emc/plugins/unity/test_client.py
Normal file
158
manila/tests/share/drivers/emc/plugins/unity/test_client.py
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from manila import exception
|
||||||
|
from manila import test
|
||||||
|
from manila.tests.share.drivers.emc.plugins.unity import res_mock
|
||||||
|
|
||||||
|
|
||||||
|
class TestClient(test.TestCase):
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_cifs_share__existed_expt(self, client, mocked_input):
|
||||||
|
resource = mocked_input['filesystem']
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
|
||||||
|
new_share = client.create_cifs_share(resource, share.name)
|
||||||
|
|
||||||
|
self.assertEqual(share.name, new_share.name)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_nfs_share__existed_expt(self, client, mocked_input):
|
||||||
|
resource = mocked_input['filesystem']
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
|
||||||
|
new_share = client.create_nfs_share(resource, share.name)
|
||||||
|
|
||||||
|
self.assertEqual(share.name, new_share.name)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_get_share_with_invalid_proto(self, client, mocked_input):
|
||||||
|
share = mocked_input['share']
|
||||||
|
|
||||||
|
self.assertRaises(exception.BadConfigurationException,
|
||||||
|
client.get_share,
|
||||||
|
share.name,
|
||||||
|
'fake_proto')
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_filesystem__existed_expt(self, client, mocked_input):
|
||||||
|
pool = mocked_input['pool']
|
||||||
|
nas_server = mocked_input['nas_server']
|
||||||
|
filesystem = mocked_input['filesystem']
|
||||||
|
|
||||||
|
new_filesystem = client.create_filesystem(pool,
|
||||||
|
nas_server,
|
||||||
|
filesystem.name,
|
||||||
|
filesystem.size,
|
||||||
|
filesystem.proto)
|
||||||
|
|
||||||
|
self.assertEqual(filesystem.name, new_filesystem.name)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_delete_filesystem__nonexistent_expt(self, client, mocked_input):
|
||||||
|
filesystem = mocked_input['filesystem']
|
||||||
|
|
||||||
|
client.delete_filesystem(filesystem)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_nas_server__existed_expt(self, client, mocked_input):
|
||||||
|
sp = mocked_input['sp']
|
||||||
|
pool = mocked_input['pool']
|
||||||
|
nas_server = mocked_input['nas_server']
|
||||||
|
|
||||||
|
new_nas_server = client.create_nas_server(nas_server.name, sp, pool)
|
||||||
|
|
||||||
|
self.assertEqual(nas_server.name, new_nas_server.name)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_delete_nas_server__nonexistent_expt(self, client, mocked_input):
|
||||||
|
nas_server = mocked_input['nas_server']
|
||||||
|
|
||||||
|
client.delete_nas_server(nas_server.name)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_dns_server__existed_expt(self, client, mocked_input):
|
||||||
|
nas_server = mocked_input['nas_server']
|
||||||
|
|
||||||
|
client.create_dns_server(nas_server, 'fake_domain', 'fake_dns_ip')
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_interface__existed_expt(self, client, mocked_input):
|
||||||
|
nas_server = mocked_input['nas_server']
|
||||||
|
port_set = ('fake_port',)
|
||||||
|
|
||||||
|
self.assertRaises(exception.IPAddressInUse, client.create_interface,
|
||||||
|
nas_server, 'fake_ip_addr', 'fake_mask',
|
||||||
|
'fake_gateway', ports=port_set)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_enable_cifs_service__existed_expt(self, client, mocked_input):
|
||||||
|
nas_server = mocked_input['nas_server']
|
||||||
|
|
||||||
|
client.enable_cifs_service(
|
||||||
|
nas_server, 'domain_name', 'fake_user', 'fake_passwd')
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_enable_nfs_service__existed_expt(self, client, mocked_input):
|
||||||
|
nas_server = mocked_input['nas_server']
|
||||||
|
|
||||||
|
client.enable_nfs_service(nas_server)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_snapshot__existed_expt(self, client, mocked_input):
|
||||||
|
nas_server = mocked_input['filesystem']
|
||||||
|
exp_snap = mocked_input['snapshot']
|
||||||
|
|
||||||
|
client.create_snapshot(nas_server, exp_snap.name)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_create_snap_of_snap__existed_expt(self, client, mocked_input):
|
||||||
|
snapshot = mocked_input['src_snapshot']
|
||||||
|
dest_snap = mocked_input['dest_snapshot']
|
||||||
|
|
||||||
|
new_snap = client.create_snap_of_snap(
|
||||||
|
snapshot, dest_snap.name, 'checkpoint')
|
||||||
|
|
||||||
|
self.assertEqual(dest_snap.name, new_snap.name)
|
||||||
|
|
||||||
|
@res_mock.mock_client_input
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_delete_snapshot__nonexistent_expt(self, client, mocked_input):
|
||||||
|
snapshot = mocked_input['snapshot']
|
||||||
|
|
||||||
|
client.delete_snapshot(snapshot)
|
||||||
|
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_nfs_deny_access__nonexistent_expt(self, client):
|
||||||
|
client.nfs_deny_access('fake_share_name', 'fake_ip_addr')
|
||||||
|
|
||||||
|
@res_mock.patch_client
|
||||||
|
def test_get_storage_processor(self, client):
|
||||||
|
sp = client.get_storage_processor(sp_id='SPA')
|
||||||
|
|
||||||
|
self.assertEqual('SPA', sp.name)
|
617
manila/tests/share/drivers/emc/plugins/unity/test_connection.py
Normal file
617
manila/tests/share/drivers/emc/plugins/unity/test_connection.py
Normal file
@ -0,0 +1,617 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import ddt
|
||||||
|
import mock
|
||||||
|
from oslo_utils import units
|
||||||
|
import six
|
||||||
|
|
||||||
|
from manila import exception
|
||||||
|
from manila import test
|
||||||
|
from manila.tests.share.drivers.emc.plugins.unity import fake_exceptions
|
||||||
|
from manila.tests.share.drivers.emc.plugins.unity import res_mock
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class TestConnection(test.TestCase):
|
||||||
|
client = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.emc_share_driver = res_mock.FakeEMCShareDriver()
|
||||||
|
|
||||||
|
@res_mock.patch_connection_init
|
||||||
|
def test_connect(self, connection):
|
||||||
|
connection.connect(res_mock.FakeEMCShareDriver(), None)
|
||||||
|
|
||||||
|
@res_mock.patch_connection_init
|
||||||
|
def test_connect__invalid_sp_configuration(self, connection):
|
||||||
|
self.assertRaises(exception.BadConfigurationException,
|
||||||
|
connection.connect,
|
||||||
|
res_mock.FakeEMCShareDriver(), None)
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_connect__invalid_pool_configuration(self, connection):
|
||||||
|
f = connection.client.system.get_pool
|
||||||
|
f.side_effect = fake_exceptions.UnityResourceNotFoundError()
|
||||||
|
|
||||||
|
self.assertRaises(exception.BadConfigurationException,
|
||||||
|
connection._config_pool,
|
||||||
|
'faked_pool_name')
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_nfs_share(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
location = connection.create_share(None, share, share_server)
|
||||||
|
|
||||||
|
exp_location = [
|
||||||
|
{'path': 'fake_ip_addr_1:/cb532599-8dc6-4c3e-bb21-74ea54be566c'},
|
||||||
|
{'path': 'fake_ip_addr_2:/cb532599-8dc6-4c3e-bb21-74ea54be566c'},
|
||||||
|
]
|
||||||
|
exp_location = sorted(exp_location, key=lambda x: sorted(x['path']))
|
||||||
|
location = sorted(location, key=lambda x: sorted(x['path']))
|
||||||
|
self.assertEqual(exp_location, location)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_cifs_share(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
location = connection.create_share(None, share, share_server)
|
||||||
|
|
||||||
|
exp_location = [
|
||||||
|
{'path': r'\\fake_ip_addr_1\716100cc-e0b4-416b-ac27-d38dd019330d'},
|
||||||
|
{'path': r'\\fake_ip_addr_2\716100cc-e0b4-416b-ac27-d38dd019330d'},
|
||||||
|
]
|
||||||
|
exp_location = sorted(exp_location, key=lambda x: sorted(x['path']))
|
||||||
|
location = sorted(location, key=lambda x: sorted(x['path']))
|
||||||
|
self.assertEqual(exp_location, location)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_share_with_invalid_proto(self, connection, mocked_input):
|
||||||
|
share = mocked_input['invalid_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidShare,
|
||||||
|
connection.create_share,
|
||||||
|
None,
|
||||||
|
share,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_share_without_share_server(self, connection,
|
||||||
|
mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
connection.create_share,
|
||||||
|
None,
|
||||||
|
share,
|
||||||
|
None)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_share__no_server_name_in_backend_details(self, connection,
|
||||||
|
mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = {
|
||||||
|
'backend_details': {'share_server_name': None},
|
||||||
|
'id': 'test',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
connection.create_share,
|
||||||
|
None,
|
||||||
|
share,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_share_with_invalid_share_server(self, connection,
|
||||||
|
mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
self.assertRaises(exception.EMCUnityError,
|
||||||
|
connection.create_share,
|
||||||
|
None,
|
||||||
|
share,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_delete_share(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.delete_share(None, share, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_delete_share__with_invalid_share(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
|
||||||
|
connection.delete_share(None, share, None)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_delete_share__create_from_snap(self, connection,
|
||||||
|
mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.delete_share(None, share, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_delete_share__create_from_snap_but_not_isolated(self,
|
||||||
|
connection,
|
||||||
|
mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.delete_share(None, share, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_delete_share__but_not_isolated(self, connection,
|
||||||
|
mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.delete_share(None, share, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_extend_cifs_share(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
new_size = 50 * units.Gi
|
||||||
|
|
||||||
|
connection.extend_share(share, new_size, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_extend_nfs_share(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
new_size = 50 * units.Gi
|
||||||
|
|
||||||
|
connection.extend_share(share, new_size, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_extend_share__create_from_snap(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
new_size = 50 * units.Gi
|
||||||
|
|
||||||
|
self.assertRaises(exception.ShareExtendingError,
|
||||||
|
connection.extend_share,
|
||||||
|
share,
|
||||||
|
new_size,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_snapshot_from_filesystem(self, connection, mocked_input):
|
||||||
|
snapshot = mocked_input['snapshot']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.create_snapshot(None, snapshot, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_snapshot_from_snapshot(self, connection, mocked_input):
|
||||||
|
snapshot = mocked_input['snapshot']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.create_snapshot(None, snapshot, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_delete_snapshot(self, connection, mocked_input):
|
||||||
|
snapshot = mocked_input['snapshot']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.delete_snapshot(None, snapshot, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_ensure_share_exists(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
|
||||||
|
connection.ensure_share(None, share, None)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_ensure_share_not_exists(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
|
||||||
|
self.assertRaises(exception.ShareNotFound,
|
||||||
|
connection.ensure_share,
|
||||||
|
None,
|
||||||
|
share,
|
||||||
|
None)
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_update_share_stats(self, connection):
|
||||||
|
stat_dict = copy.deepcopy(res_mock.STATS)
|
||||||
|
|
||||||
|
connection.update_share_stats(stat_dict)
|
||||||
|
self.assertEqual(5, len(stat_dict))
|
||||||
|
pool = stat_dict['pools'][0]
|
||||||
|
self.assertEqual('pool_1', pool['pool_name'])
|
||||||
|
self.assertEqual(500000.0, pool['total_capacity_gb'])
|
||||||
|
self.assertEqual(False, pool['qos'])
|
||||||
|
self.assertEqual(30000.0, pool['provisioned_capacity_gb'])
|
||||||
|
self.assertEqual(20, pool['max_over_subscription_ratio'])
|
||||||
|
self.assertEqual(10000.0, pool['allocated_capacity_gb'])
|
||||||
|
self.assertEqual(0, pool['reserved_percentage'])
|
||||||
|
self.assertTrue(pool['thin_provisioning'])
|
||||||
|
self.assertEqual(490000.0, pool['free_capacity_gb'])
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_update_share_stats__nonexistent_pools(self, connection):
|
||||||
|
stat_dict = copy.deepcopy(res_mock.STATS)
|
||||||
|
|
||||||
|
self.assertRaises(exception.EMCUnityError,
|
||||||
|
connection.update_share_stats,
|
||||||
|
stat_dict)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_get_pool(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
|
||||||
|
connection.get_pool(share)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_setup_server(self, connection, mocked_input):
|
||||||
|
network_info = mocked_input['network_info__flat']
|
||||||
|
|
||||||
|
connection.setup_server(network_info)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_setup_server__vlan_network(self, connection, mocked_input):
|
||||||
|
network_info = mocked_input['network_info__vlan']
|
||||||
|
|
||||||
|
connection.setup_server(network_info)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_setup_server__vxlan_network(self, connection, mocked_input):
|
||||||
|
network_info = mocked_input['network_info__vxlan']
|
||||||
|
|
||||||
|
self.assertRaises(exception.NetworkBadConfigurationException,
|
||||||
|
connection.setup_server,
|
||||||
|
network_info)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_setup_server__active_directory(self, connection, mocked_input):
|
||||||
|
network_info = mocked_input['network_info__active_directory']
|
||||||
|
|
||||||
|
connection.setup_server(network_info)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_setup_server__kerberos(self, connection, mocked_input):
|
||||||
|
network_info = mocked_input['network_info__kerberos']
|
||||||
|
|
||||||
|
connection.setup_server(network_info)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_setup_server__throw_exception(self, connection, mocked_input):
|
||||||
|
network_info = mocked_input['network_info__flat']
|
||||||
|
|
||||||
|
self.assertRaises(fake_exceptions.UnityException,
|
||||||
|
connection.setup_server,
|
||||||
|
network_info)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_teardown_server(self, connection, mocked_input):
|
||||||
|
server_detail = mocked_input['server_detail']
|
||||||
|
security_services = mocked_input['security_services']
|
||||||
|
|
||||||
|
connection.teardown_server(server_detail, security_services)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_teardown_server__no_server_detail(self, connection, mocked_input):
|
||||||
|
security_services = mocked_input['security_services']
|
||||||
|
|
||||||
|
connection.teardown_server(None, security_services)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_teardown_server__no_share_server_name(self, connection,
|
||||||
|
mocked_input):
|
||||||
|
server_detail = {'share_server_name': None}
|
||||||
|
security_services = mocked_input['security_services']
|
||||||
|
|
||||||
|
connection.teardown_server(server_detail, security_services)
|
||||||
|
|
||||||
|
@ddt.data({'configured_pools': None,
|
||||||
|
'matched_pools': {'pool_1', 'pool_2', 'nas_server_pool'}},
|
||||||
|
{'configured_pools': ['*'],
|
||||||
|
'matched_pools': {'pool_1', 'pool_2', 'nas_server_pool'}},
|
||||||
|
{'configured_pools': ['pool_*'],
|
||||||
|
'matched_pools': {'pool_1', 'pool_2'}},
|
||||||
|
{'configured_pools': ['*pool'],
|
||||||
|
'matched_pools': {'nas_server_pool'}},
|
||||||
|
{'configured_pools': ['nas_server_pool'],
|
||||||
|
'matched_pools': {'nas_server_pool'}},
|
||||||
|
{'configured_pools': ['nas_*', 'pool_*'],
|
||||||
|
'matched_pools': {'pool_1', 'pool_2', 'nas_server_pool'}})
|
||||||
|
@res_mock.patch_connection
|
||||||
|
@ddt.unpack
|
||||||
|
def test__get_managed_pools(self, connection, mocked_input):
|
||||||
|
configured_pools = mocked_input['configured_pools']
|
||||||
|
matched_pool = mocked_input['matched_pools']
|
||||||
|
|
||||||
|
pools = connection._get_managed_pools(configured_pools)
|
||||||
|
|
||||||
|
self.assertEqual(matched_pool, pools)
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test__get_managed_pools__invalid_pool_configuration(self, connection):
|
||||||
|
configured_pools = 'fake_pool'
|
||||||
|
|
||||||
|
self.assertRaises(exception.BadConfigurationException,
|
||||||
|
connection._get_managed_pools,
|
||||||
|
configured_pools)
|
||||||
|
|
||||||
|
@ddt.data({'configured_ports': None,
|
||||||
|
'matched_ports': {'spa_eth1', 'spa_eth2'}},
|
||||||
|
{'configured_ports': ['*'],
|
||||||
|
'matched_ports': {'spa_eth1', 'spa_eth2'}},
|
||||||
|
{'configured_ports': ['spa_*'],
|
||||||
|
'matched_ports': {'spa_eth1', 'spa_eth2'}},
|
||||||
|
{'configured_ports': ['*_eth1'],
|
||||||
|
'matched_ports': {'spa_eth1'}},
|
||||||
|
{'configured_ports': ['spa_eth1'],
|
||||||
|
'matched_ports': {'spa_eth1'}},
|
||||||
|
{'configured_ports': ['spa_eth1', 'spa_eth2'],
|
||||||
|
'matched_ports': {'spa_eth1', 'spa_eth2'}})
|
||||||
|
@res_mock.patch_connection
|
||||||
|
@ddt.unpack
|
||||||
|
def test__get_managed_ports(self, connection, mocked_input):
|
||||||
|
sp = mock.Mock()
|
||||||
|
sp.id = 'SPA'
|
||||||
|
configured_ports = mocked_input['configured_ports']
|
||||||
|
matched_ports = mocked_input['matched_ports']
|
||||||
|
|
||||||
|
ports = connection._get_managed_ports(configured_ports, sp)
|
||||||
|
|
||||||
|
self.assertEqual(matched_ports, ports)
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test__get_managed_ports__invalid_port_configuration(self, connection):
|
||||||
|
configured_ports = 'fake_port'
|
||||||
|
sp = mock.Mock()
|
||||||
|
sp.id = 'SPA'
|
||||||
|
|
||||||
|
self.assertRaises(exception.BadConfigurationException,
|
||||||
|
connection._get_managed_ports,
|
||||||
|
configured_ports,
|
||||||
|
sp)
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test__get_pool_name_from_host__no_pool_name(self, connection):
|
||||||
|
host = 'openstack@Unity'
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidHost,
|
||||||
|
connection._get_pool_name_from_host,
|
||||||
|
host)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_cifs_share_from_snapshot(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
snapshot = mocked_input['snapshot']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.create_share_from_snapshot(None, share, snapshot,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_nfs_share_from_snapshot(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
snapshot = mocked_input['snapshot']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.create_share_from_snapshot(None, share, snapshot,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_create_share_from_snapshot_no_server_name(self,
|
||||||
|
connection,
|
||||||
|
mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
snapshot = mocked_input['snapshot']
|
||||||
|
share_server = mocked_input['share_server__no_share_server_name']
|
||||||
|
|
||||||
|
self.assertRaises(exception.EMCUnityError,
|
||||||
|
connection.create_share_from_snapshot,
|
||||||
|
None,
|
||||||
|
share,
|
||||||
|
snapshot,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_clear_share_access_cifs(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
|
||||||
|
self.assertRaises(fake_exceptions.UnityException,
|
||||||
|
connection.clear_access,
|
||||||
|
share)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_clear_share_access_nfs(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
|
||||||
|
self.assertRaises(fake_exceptions.UnityException,
|
||||||
|
connection.clear_access,
|
||||||
|
share)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_allow_rw_cifs_share_access(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
rw_access = mocked_input['cifs_rw_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.allow_access(None, share, rw_access, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_update_access_allow_rw(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
rw_access = mocked_input['cifs_rw_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.update_access(None, share, None, [rw_access], None,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_update_access_recovery(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
rw_access = mocked_input['cifs_rw_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.update_access(None, share, [rw_access], None, None,
|
||||||
|
share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_allow_ro_cifs_share_access(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
rw_access = mocked_input['cifs_ro_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.allow_access(None, share, rw_access, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_allow_rw_nfs_share_access(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
rw_access = mocked_input['nfs_rw_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.allow_access(None, share, rw_access, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_allow_rw_nfs_share_access_cidr(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
rw_access = mocked_input['nfs_rw_access_cidr']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.allow_access(None, share, rw_access, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_allow_ro_nfs_share_access(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
ro_access = mocked_input['nfs_ro_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.allow_access(None, share, ro_access, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_deny_cifs_share_access(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
rw_access = mocked_input['cifs_rw_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.deny_access(None, share, rw_access, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_deny_nfs_share_access(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
rw_access = mocked_input['nfs_rw_access']
|
||||||
|
share_server = mocked_input['share_server']
|
||||||
|
|
||||||
|
connection.deny_access(None, share, rw_access, share_server)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_update_access_deny_nfs(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
rw_access = mocked_input['nfs_rw_access']
|
||||||
|
|
||||||
|
connection.update_access(None, share, None, None, [rw_access], None)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test__validate_cifs_share_access_type(self, connection, mocked_input):
|
||||||
|
share = mocked_input['cifs_share']
|
||||||
|
rw_access = mocked_input['invalid_access']
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidShareAccess,
|
||||||
|
connection._validate_share_access_type,
|
||||||
|
share,
|
||||||
|
rw_access)
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test__validate_nfs_share_access_type(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
rw_access = mocked_input['invalid_access']
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidShareAccess,
|
||||||
|
connection._validate_share_access_type,
|
||||||
|
share,
|
||||||
|
rw_access)
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_get_network_allocations_number(self, connection):
|
||||||
|
self.assertEqual(2, connection.get_network_allocations_number())
|
||||||
|
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_get_proto_enum(self, connection):
|
||||||
|
self.assertIn('FSSupportedProtocolEnum.CIFS',
|
||||||
|
six.text_type(connection._get_proto_enum('CIFS')))
|
||||||
|
self.assertIn('FSSupportedProtocolEnum.NFS',
|
||||||
|
six.text_type(connection._get_proto_enum('nfs')))
|
||||||
|
|
||||||
|
@res_mock.mock_manila_input
|
||||||
|
@res_mock.patch_connection
|
||||||
|
def test_allow_access_error_access_level(self, connection, mocked_input):
|
||||||
|
share = mocked_input['nfs_share']
|
||||||
|
rw_access = mocked_input['invalid_access']
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidShareAccessLevel,
|
||||||
|
connection.allow_access,
|
||||||
|
None, share, rw_access)
|
50
manila/tests/share/drivers/emc/plugins/unity/test_utils.py
Normal file
50
manila/tests/share/drivers/emc/plugins/unity/test_utils.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import ddt
|
||||||
|
|
||||||
|
from manila.share.drivers.emc.plugins.unity import utils
|
||||||
|
from manila import test
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class TestUtils(test.TestCase):
|
||||||
|
@ddt.data({'matcher': None,
|
||||||
|
'matched': {'pool_1', 'pool_2', 'nas_server_pool'},
|
||||||
|
'not_matched': set()},
|
||||||
|
{'matcher': ['*'],
|
||||||
|
'matched': {'pool_1', 'pool_2', 'nas_server_pool'},
|
||||||
|
'not_matched': set()},
|
||||||
|
{'matcher': ['pool_*'],
|
||||||
|
'matched': {'pool_1', 'pool_2'},
|
||||||
|
'not_matched': {'nas_server_pool'}},
|
||||||
|
{'matcher': ['*pool'],
|
||||||
|
'matched': {'nas_server_pool'},
|
||||||
|
'not_matched': {'pool_1', 'pool_2'}},
|
||||||
|
{'matcher': ['nas_server_pool'],
|
||||||
|
'matched': {'nas_server_pool'},
|
||||||
|
'not_matched': {'pool_1', 'pool_2'}},
|
||||||
|
{'matcher': ['nas_*', 'pool_*'],
|
||||||
|
'matched': {'pool_1', 'pool_2', 'nas_server_pool'},
|
||||||
|
'not_matched': set()})
|
||||||
|
def test_do_match(self, data):
|
||||||
|
full = ['pool_1 ', ' pool_2', ' nas_server_pool ']
|
||||||
|
matcher = data['matcher']
|
||||||
|
expected_matched = data['matched']
|
||||||
|
expected_not_matched = data['not_matched']
|
||||||
|
|
||||||
|
matched, not_matched = utils.do_match(full, matcher)
|
||||||
|
self.assertEqual(expected_matched, matched)
|
||||||
|
self.assertEqual(expected_not_matched, not_matched)
|
32
manila/tests/share/drivers/emc/plugins/unity/utils.py
Normal file
32
manila/tests/share/drivers/emc/plugins/unity/utils.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2016 EMC Corporation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from os import path
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
patch_system = mock.patch('storops.UnitySystem')
|
||||||
|
|
||||||
|
|
||||||
|
def load_yaml(file_name):
|
||||||
|
yaml_file = '{}/{}'.format(path.dirname(path.abspath(__file__)), file_name)
|
||||||
|
with open(yaml_file) as f:
|
||||||
|
res = yaml.load(f)
|
||||||
|
LOG.debug('Loaded yaml mock objects from %s.', yaml_file)
|
||||||
|
return res
|
@ -84,16 +84,19 @@ class StorageConnectionTestCase(test.TestCase):
|
|||||||
@ddt.data({'pool_conf': None,
|
@ddt.data({'pool_conf': None,
|
||||||
'real_pools': ['fake_pool', 'nas_pool'],
|
'real_pools': ['fake_pool', 'nas_pool'],
|
||||||
'matched_pool': set()},
|
'matched_pool': set()},
|
||||||
{'pool_conf': '*',
|
{'pool_conf': [],
|
||||||
|
'real_pools': ['fake_pool', 'nas_pool'],
|
||||||
|
'matched_pool': set()},
|
||||||
|
{'pool_conf': ['*'],
|
||||||
'real_pools': ['fake_pool', 'nas_pool'],
|
'real_pools': ['fake_pool', 'nas_pool'],
|
||||||
'matched_pool': {'fake_pool', 'nas_pool'}},
|
'matched_pool': {'fake_pool', 'nas_pool'}},
|
||||||
{'pool_conf': 'fake_*',
|
{'pool_conf': ['fake_*'],
|
||||||
'real_pools': ['fake_pool', 'nas_pool', 'Perf_Pool'],
|
'real_pools': ['fake_pool', 'nas_pool', 'Perf_Pool'],
|
||||||
'matched_pool': {'fake_pool'}},
|
'matched_pool': {'fake_pool'}},
|
||||||
{'pool_conf': '*pool',
|
{'pool_conf': ['*pool'],
|
||||||
'real_pools': ['fake_pool', 'NAS_Pool', 'Perf_POOL'],
|
'real_pools': ['fake_pool', 'NAS_Pool', 'Perf_POOL'],
|
||||||
'matched_pool': {'fake_pool'}},
|
'matched_pool': {'fake_pool'}},
|
||||||
{'pool_conf': 'nas_pool',
|
{'pool_conf': ['nas_pool'],
|
||||||
'real_pools': ['fake_pool', 'nas_pool', 'perf_pool'],
|
'real_pools': ['fake_pool', 'nas_pool', 'perf_pool'],
|
||||||
'matched_pool': {'nas_pool'}})
|
'matched_pool': {'nas_pool'}})
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
@ -120,11 +123,11 @@ class StorageConnectionTestCase(test.TestCase):
|
|||||||
xml_req_mock.assert_has_calls(expected_calls)
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
@ddt.data(
|
@ddt.data(
|
||||||
{'pool_conf': 'fake_*',
|
{'pool_conf': ['fake_*'],
|
||||||
'real_pools': ['nas_pool', 'Perf_Pool']},
|
'real_pools': ['nas_pool', 'Perf_Pool']},
|
||||||
{'pool_conf': '*pool',
|
{'pool_conf': ['*pool'],
|
||||||
'real_pools': ['NAS_Pool', 'Perf_POOL']},
|
'real_pools': ['NAS_Pool', 'Perf_POOL']},
|
||||||
{'pool_conf': 'nas_pool',
|
{'pool_conf': ['nas_pool'],
|
||||||
'real_pools': ['fake_pool', 'perf_pool']},
|
'real_pools': ['fake_pool', 'perf_pool']},
|
||||||
)
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
Add a new EMC Unity plugin in manila which allows user to create NFS/CIFS
|
||||||
|
share with a EMC Unity backend.
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add a new Unity plugin in manila which allows user to create NFS/CIFS
|
||||||
|
share with a EMC Unity backend. This plugin performs the operations on
|
||||||
|
Unity by REST API.
|
||||||
|
issues:
|
||||||
|
- EMC Unity does not support the same IP in different VLANs.
|
@ -60,6 +60,7 @@ oslo.config.opts.defaults =
|
|||||||
manila = manila.common.config:set_middleware_defaults
|
manila = manila.common.config:set_middleware_defaults
|
||||||
manila.share.drivers.emc.plugins =
|
manila.share.drivers.emc.plugins =
|
||||||
vnx = manila.share.drivers.emc.plugins.vnx.connection:VNXStorageConnection
|
vnx = manila.share.drivers.emc.plugins.vnx.connection:VNXStorageConnection
|
||||||
|
unity = manila.share.drivers.emc.plugins.unity.connection:UnityStorageConnection
|
||||||
isilon = manila.share.drivers.emc.plugins.isilon.isilon:IsilonStorageConnection
|
isilon = manila.share.drivers.emc.plugins.isilon.isilon:IsilonStorageConnection
|
||||||
manila.tests.scheduler.fakes =
|
manila.tests.scheduler.fakes =
|
||||||
FakeWeigher1 = manila.tests.scheduler.fakes:FakeWeigher1
|
FakeWeigher1 = manila.tests.scheduler.fakes:FakeWeigher1
|
||||||
|
Loading…
Reference in New Issue
Block a user