Merge "Refactor HP 3PAR share driver to now be HPE"

This commit is contained in:
Jenkins 2015-11-18 02:29:48 +00:00 committed by Gerrit Code Review
commit 0c549ead18
13 changed files with 396 additions and 359 deletions

View File

@ -13,16 +13,21 @@
License for the specific language governing permissions and limitations
under the License.
HP 3PAR Driver
HPE 3PAR Driver
==============
The HP 3PAR Manila driver provides NFS and CIFS shared file systems to
OpenStack using HP 3PAR's File Persona capabilities.
The HPE 3PAR Manila driver provides NFS and CIFS shared file systems to
OpenStack using HPE 3PAR's File Persona capabilities.
.. note::
In OpenStack releases prior to Mitaka this driver was called the
HP 3PAR driver. The Liberty configuration reference can be found
at: http://docs.openstack.org/liberty/config-reference/content/hp-3par-share-driver.html
Supported Operations
--------------------
The following operations are supported with HP 3PAR File Persona:
The following operations are supported with HPE 3PAR File Persona:
- Create/delete NFS and CIFS shares
@ -58,18 +63,18 @@ Requirements
On the system running the Manila share service:
- hp3parclient version 3.2.1 or newer from PyPI
- python-3parclient 4.0.0 or newer from PyPI.
On the HP 3PAR array:
On the HPE 3PAR array:
- HP 3PAR Operating System software version 3.2.1 MU3 or higher
- HPE 3PAR Operating System software version 3.2.1 MU3 or higher
- A license that enables the File Persona feature
- The array class and hardware configuration must support File Persona
Pre-Configuration on the HP 3PAR
Pre-Configuration on the HPE 3PAR
--------------------------------
- HP 3PAR File Persona must be initialized and started (:code:`startfs`)
- HPE 3PAR File Persona must be initialized and started (:code:`startfs`)
- A File Provisioning Group (FPG) must be created for use with Manila
- A Virtual File Server (VFS) must be created for the FPG
- The VFS must be configured with an appropriate share export IP address
@ -79,22 +84,22 @@ Backend Configuration
---------------------
The following parameters need to be configured in the Manila configuration
file for the HP 3PAR driver:
file for the HPE 3PAR driver:
- `share_backend_name` = <backend name to enable>
- `share_driver` = manila.share.drivers.hp.hp_3par_driver.HP3ParShareDriver
- `share_driver` = manila.share.drivers.hpe.hpe_3par_driver.HPE3ParShareDriver
- `driver_handles_share_servers` = False
- `hp3par_fpg` = <FPG to use for share creation>
- `hp3par_share_ip_address` = <IP address to use for share export location>
- `hp3par_san_ip` = <IP address for SSH access to the SAN controller>
- `hp3par_api_url` = <3PAR WS API Server URL>
- `hp3par_username` = <3PAR username with the 'edit' role>
- `hp3par_password` = <3PAR password for the user specified in hp3par_username>
- `hp3par_san_login` = <Username for SSH access to the SAN controller>
- `hp3par_san_password` = <Password for SSH access to the SAN controller>
- `hp3par_debug` = <False or True for extra debug logging>
- `hpe3par_fpg` = <FPG to use for share creation>
- `hpe3par_share_ip_address` = <IP address to use for share export location>
- `hpe3par_san_ip` = <IP address for SSH access to the SAN controller>
- `hpe3par_api_url` = <3PAR WS API Server URL>
- `hpe3par_username` = <3PAR username with the 'edit' role>
- `hpe3par_password` = <3PAR password for the user specified in hpe3par_username>
- `hpe3par_san_login` = <Username for SSH access to the SAN controller>
- `hpe3par_san_password` = <Password for SSH access to the SAN controller>
- `hpe3par_debug` = <False or True for extra debug logging>
The `hp3par_share_ip_address` must be a valid IP address for the configured
The `hpe3par_share_ip_address` must be a valid IP address for the configured
FPG's VFS. This IP address is used in export locations for shares that are
created. Networking must be configured to allow connectivity from clients to
shares.
@ -127,23 +132,23 @@ Manila requires that the share type includes the
`driver_handles_share_servers` extra-spec. This ensures that the share
will be created on a backend that supports the requested
driver_handles_share_servers (share networks) capability.
For the HP 3PAR driver, this must be set to False.
For the HPE 3PAR driver, this must be set to False.
Another common Manila extra-spec used to determine where a share is created
is `share_backend_name`. When this extra-spec is defined in the share type,
the share will be created on a backend with a matching share_backend_name.
The HP 3PAR driver automatically reports capabilities based on the FPG used
The HPE 3PAR driver automatically reports capabilities based on the FPG used
for each backend. Share types with extra specs can be created by an
administrator to control which share types are allowed to use FPGs with or
without specific capabilities. The following extra-specs are used with
the capabilities filter and the HP 3PAR driver:
the capabilities filter and the HPE 3PAR driver:
- `hp3par_flash_cache` = '<is> True' or '<is> False'
- `hpe3par_flash_cache` = '<is> True' or '<is> False'
- `thin_provisioning` = '<is> True' or '<is> False'
- `dedupe` = '<is> True' or '<is> False'
`hp3par_flash_cache` will be reported as True for backends that have
`hpe3par_flash_cache` will be reported as True for backends that have
3PAR's Adaptive Flash Cache enabled.
`thin_provisioning` will be reported as True for backends that use thin
@ -155,14 +160,16 @@ over-subscription feature.
technology.
Scoped extra-specs are used to influence vendor-specific implementation
details. Scoped extra-specs use a prefix followed by a colon. For HP 3PAR
these extra-specs have a prefix of `hp3par`.
details. Scoped extra-specs use a prefix followed by a colon. For HPE 3PAR
these extra-specs have a prefix of `hpe3par`. For HP 3PAR these extra-specs
have a prefix of `hp3par`.
The following HP 3PAR extra-specs are used when creating CIFS (SMB) shares:
The following HPE 3PAR extra-specs are used when creating CIFS (SMB) shares:
- `hpe3par:smb_access_based_enum` = true or false
- `hpe3par:smb_continuous_avail` = true or false
- `hpe3par:smb_cache` = off, manual, optimized or auto
- `hp3par:smb_access_based_enum` = true or false
- `hp3par:smb_continuous_avail` = true or false
- `hp3par:smb_cache` = off, manual, optimized or auto
`smb_access_based_enum` (Access Based Enumeration) specifies if users can see
only the files and directories to which they have been allowed access on the
@ -188,25 +195,25 @@ or earlier.
documents.
* If this is not specified, the default is `manual`.
The following HP 3PAR extra-specs are used when creating NFS shares:
The following HPE 3PAR extra-specs are used when creating NFS shares:
- `hp3par:nfs_options` = Comma separated list of NFS export options
- `hpe3par:nfs_options` = Comma separated list of NFS export options
The NFS export options have the following limitations:
* `ro` and `rw` are not allowed (Manila will determine the read-only option)
* `no_subtree_check` and `fsid` are not allowed per HP 3PAR CLI support
* `(in)secure` and `(no_)root_squash` are not allowed because the HP 3PAR
* `no_subtree_check` and `fsid` are not allowed per HPE 3PAR CLI support
* `(in)secure` and `(no_)root_squash` are not allowed because the HPE 3PAR
driver controls those settings
All other NFS options are forwarded to the HP 3PAR as part of share creation.
The HP 3PAR will do additional validation at share creation time. Refer to
HP 3PAR CLI help for more details.
All other NFS options are forwarded to the HPE 3PAR as part of share creation.
The HPE 3PAR will do additional validation at share creation time. Refer to
HPE 3PAR CLI help for more details.
The :mod:`manila.share.drivers.hp.hp_3par_driver` Module
The :mod:`manila.share.drivers.hpe.hpe_3par_driver` Module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. automodule:: manila.share.drivers.hp.hp_3par_driver
.. automodule:: manila.share.drivers.hpe.hpe_3par_driver
:noindex:
:members:
:undoc-members:

View File

@ -107,7 +107,7 @@ Share backends
huawei_nas_driver
hdfs_native_driver
hds_hnas_driver
hp_3par_driver
hpe_3par_driver
Indices and tables
------------------

View File

@ -49,7 +49,7 @@ Mapping of share drivers and share features support
+----------------------------------------+-----------------------------+-----------------------+--------------+--------------+------------------------+----------------------------+
| Hitachi HNAS | DHSS = False (L) | L | L | \- | L | L |
+----------------------------------------+-----------------------------+-----------------------+--------------+--------------+------------------------+----------------------------+
| HP 3PAR | DHSS = True (L) & False (K) | \- | \- | \- | K | K |
| HPE 3PAR | DHSS = True (L) & False (K) | \- | \- | \- | K | K |
+----------------------------------------+-----------------------------+-----------------------+--------------+--------------+------------------------+----------------------------+
| Huawei | DHSS = False(K) | L | L | L | K | \- |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@ -90,7 +90,7 @@ Mapping of share drivers and share access rules support
+----------------------------------------+--------------+------------+------------+--------------+------------+------------+
| Hitachi HNAS | NFS (L) | \- | \- | NFS (L) | \- | \- |
+----------------------------------------+--------------+------------+------------+--------------+------------+------------+
| HP 3PAR | NFS,CIFS (K) | CIFS (K) | \- | \- | \- | \- |
| HPE 3PAR | NFS,CIFS (K) | CIFS (K) | \- | \- | \- | \- |
+----------------------------------------+--------------+------------+------------+--------------+------------+------------+
| Huawei | NFS (K) | CIFS (K) | \- | NFS (K) | CIFS (K) | \- |
+----------------------------------------+--------------+------------+------------+--------------+------------+------------+
@ -125,7 +125,7 @@ Mapping of share drivers and security services support
+----------------------------------------+------------------+-----------------+------------------+
| Hitachi HNAS | \- | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+
| HP 3PAR | \- | \- | \- |
| HPE 3PAR | \- | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+
| Huawei | \- | \- | \- |
+----------------------------------------+------------------+-----------------+------------------+

View File

@ -599,15 +599,15 @@ class EMCVnxInvalidMoverID(ManilaException):
message = _("Invalid mover or vdm %(id)s.")
class HP3ParInvalidClient(Invalid):
class HPE3ParInvalidClient(Invalid):
message = _("%(err)s")
class HP3ParInvalid(Invalid):
class HPE3ParInvalid(Invalid):
message = _("%(err)s")
class HP3ParUnexpectedError(ManilaException):
class HPE3ParUnexpectedError(ManilaException):
message = _("%(err)s")

View File

@ -60,7 +60,7 @@ import manila.share.drivers.glusterfs.layout_directory
import manila.share.drivers.glusterfs.layout_volume
import manila.share.drivers.hdfs.hdfs_native
import manila.share.drivers.hitachi.hds_hnas
import manila.share.drivers.hp.hp_3par_driver
import manila.share.drivers.hpe.hpe_3par_driver
import manila.share.drivers.huawei.huawei_nas
import manila.share.drivers.ibm.gpfs
import manila.share.drivers.netapp.options
@ -122,7 +122,7 @@ _global_opt_lists = [
manila.share.drivers.glusterfs.layout_volume.glusterfs_volume_mapped_opts,
manila.share.drivers.hdfs.hdfs_native.hdfs_native_share_opts,
manila.share.drivers.hitachi.hds_hnas.hds_hnas_opts,
manila.share.drivers.hp.hp_3par_driver.HP3PAR_OPTS,
manila.share.drivers.hpe.hpe_3par_driver.HPE3PAR_OPTS,
manila.share.drivers.huawei.huawei_nas.huawei_opts,
manila.share.drivers.ibm.gpfs.gpfs_share_opts,
manila.share.drivers.netapp.options.netapp_proxy_opts,

View File

@ -1,4 +1,4 @@
# Copyright 2015 Hewlett Packard Development Company, L.P.
# Copyright 2015 Hewlett Packard Enterprise Development LP
#
# 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
@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
"""HP 3PAR Driver for OpenStack Manila."""
"""HPE 3PAR Driver for OpenStack Manila."""
import datetime
import hashlib
@ -29,79 +29,93 @@ from manila import exception
from manila.i18n import _
from manila.i18n import _LI
from manila.share import driver
from manila.share.drivers.hp import hp_3par_mediator
from manila.share.drivers.hpe import hpe_3par_mediator
from manila.share import share_types
from manila import utils
HP3PAR_OPTS = [
cfg.StrOpt('hp3par_api_url',
HPE3PAR_OPTS = [
cfg.StrOpt('hpe3par_api_url',
default='',
help="3PAR WSAPI Server Url like "
"https://<3par ip>:8080/api/v1"),
cfg.StrOpt('hp3par_username',
"https://<3par ip>:8080/api/v1",
deprecated_name='hp3par_api_url'),
cfg.StrOpt('hpe3par_username',
default='',
help="3PAR username with the 'edit' role"),
cfg.StrOpt('hp3par_password',
help="3PAR username with the 'edit' role",
deprecated_name='hp3par_username'),
cfg.StrOpt('hpe3par_password',
default='',
help="3PAR password for the user specified in hp3par_username",
secret=True),
cfg.StrOpt('hp3par_san_ip',
help="3PAR password for the user specified in hpe3par_username",
secret=True,
deprecated_name='hp3par_password'),
cfg.StrOpt('hpe3par_san_ip',
default='',
help="IP address of SAN controller"),
cfg.StrOpt('hp3par_san_login',
help="IP address of SAN controller",
deprecated_name='hp3par_san_ip'),
cfg.StrOpt('hpe3par_san_login',
default='',
help="Username for SAN controller"),
cfg.StrOpt('hp3par_san_password',
help="Username for SAN controller",
deprecated_name='hp3par_san_login'),
cfg.StrOpt('hpe3par_san_password',
default='',
help="Password for SAN controller",
secret=True),
cfg.PortOpt('hp3par_san_ssh_port',
secret=True,
deprecated_name='hp3par_san_password'),
cfg.PortOpt('hpe3par_san_ssh_port',
default=22,
help='SSH port to use with SAN'),
cfg.StrOpt('hp3par_fpg',
help='SSH port to use with SAN',
deprecated_name='hp3par_san_ssh_port'),
cfg.StrOpt('hpe3par_fpg',
default="OpenStack",
help="The File Provisioning Group (FPG) to use"),
cfg.StrOpt('hp3par_share_ip_address',
help="The File Provisioning Group (FPG) to use",
deprecated_name='hp3par_fpg'),
cfg.StrOpt('hpe3par_share_ip_address',
default='',
help="The IP address for shares not using a share server"),
cfg.BoolOpt('hp3par_fstore_per_share',
help="The IP address for shares not using a share server",
deprecated_name='hp3par_share_ip_address'),
cfg.BoolOpt('hpe3par_fstore_per_share',
default=False,
help="Use one filestore per share"),
cfg.BoolOpt('hp3par_debug',
help="Use one filestore per share",
deprecated_name='hp3par_fstore_per_share'),
cfg.BoolOpt('hpe3par_debug',
default=False,
help="Enable HTTP debugging to 3PAR"),
help="Enable HTTP debugging to 3PAR",
deprecated_name='hp3par_debug'),
]
CONF = cfg.CONF
CONF.register_opts(HP3PAR_OPTS)
CONF.register_opts(HPE3PAR_OPTS)
LOG = log.getLogger(__name__)
class HP3ParShareDriver(driver.ShareDriver):
"""HP 3PAR driver for Manila.
class HPE3ParShareDriver(driver.ShareDriver):
"""HPE 3PAR driver for Manila.
Supports NFS and CIFS protocols on arrays with File Persona.
Version history:
1.0.00 - Begin Liberty development (post-Kilo)
1.0.01 - Report thin/dedup/hp_flash_cache capabilities
1.0.02 - Add share server/share network support
1.0.0 - Begin Liberty development (post-Kilo)
1.0.1 - Report thin/dedup/hp_flash_cache capabilities
1.0.2 - Add share server/share network support
2.0.0 - Rebranded HP to HPE
"""
VERSION = "1.0.02"
VERSION = "2.0.0"
def __init__(self, *args, **kwargs):
super(HP3ParShareDriver, self).__init__((True, False), *args, **kwargs)
super(HPE3ParShareDriver, self).__init__((True, False),
*args,
**kwargs)
self.configuration = kwargs.get('configuration', None)
self.configuration.append_config_values(HP3PAR_OPTS)
self.configuration.append_config_values(HPE3PAR_OPTS)
self.configuration.append_config_values(driver.ssh_opts)
self.fpg = None
self.vfs = None
self.share_ip_address = None
self._hp3par = None # mediator between driver and client
self._hpe3par = None # mediator between driver and client
def do_setup(self, context):
"""Any initialization the share driver does while starting."""
@ -111,46 +125,47 @@ class HP3ParShareDriver(driver.ShareDriver):
'version': self.VERSION})
if not self.driver_handles_share_servers:
self.share_ip_address = self.configuration.hp3par_share_ip_address
self.share_ip_address = self.configuration.hpe3par_share_ip_address
if not self.share_ip_address:
raise exception.HP3ParInvalid(
raise exception.HPE3ParInvalid(
_("Unsupported configuration. "
"hp3par_share_ip_address must be set when "
"hpe3par_share_ip_address must be set when "
"driver_handles_share_servers is False."))
mediator = hp_3par_mediator.HP3ParMediator(
hp3par_username=self.configuration.hp3par_username,
hp3par_password=self.configuration.hp3par_password,
hp3par_api_url=self.configuration.hp3par_api_url,
hp3par_debug=self.configuration.hp3par_debug,
hp3par_san_ip=self.configuration.hp3par_san_ip,
hp3par_san_login=self.configuration.hp3par_san_login,
hp3par_san_password=self.configuration.hp3par_san_password,
hp3par_san_ssh_port=self.configuration.hp3par_san_ssh_port,
hp3par_fstore_per_share=self.configuration.hp3par_fstore_per_share,
mediator = hpe_3par_mediator.HPE3ParMediator(
hpe3par_username=self.configuration.hpe3par_username,
hpe3par_password=self.configuration.hpe3par_password,
hpe3par_api_url=self.configuration.hpe3par_api_url,
hpe3par_debug=self.configuration.hpe3par_debug,
hpe3par_san_ip=self.configuration.hpe3par_san_ip,
hpe3par_san_login=self.configuration.hpe3par_san_login,
hpe3par_san_password=self.configuration.hpe3par_san_password,
hpe3par_san_ssh_port=self.configuration.hpe3par_san_ssh_port,
hpe3par_fstore_per_share=(self.configuration
.hpe3par_fstore_per_share),
ssh_conn_timeout=self.configuration.ssh_conn_timeout,
)
mediator.do_setup()
# FPG must be configured and must exist.
self.fpg = self.configuration.safe_get('hp3par_fpg')
self.fpg = self.configuration.safe_get('hpe3par_fpg')
# Validate the FPG and discover the VFS
# This also validates the client, connection, firmware, WSAPI, FPG...
self.vfs = mediator.get_vfs_name(self.fpg)
# Don't set _hp3par until it is ready. Otherwise _update_stats fails.
self._hp3par = mediator
# Don't set _hpe3par until it is ready. Otherwise _update_stats fails.
self._hpe3par = mediator
def check_for_setup_error(self):
try:
# Log the source SHA for support. Only do this with DEBUG.
if LOG.isEnabledFor(logging.DEBUG):
LOG.debug('HP3ParShareDriver SHA1: %s',
self.sha1_hash(HP3ParShareDriver))
LOG.debug('HP3ParMediator SHA1: %s',
self.sha1_hash(hp_3par_mediator.HP3ParMediator))
LOG.debug('HPE3ParShareDriver SHA1: %s',
self.sha1_hash(HPE3ParShareDriver))
LOG.debug('HPE3ParMediator SHA1: %s',
self.sha1_hash(hpe_3par_mediator.HPE3ParMediator))
except Exception as e:
# Don't let any exceptions during the SHA1 logging interfere
# with startup. This is just debug info to identify the source
@ -192,7 +207,7 @@ class HP3ParShareDriver(driver.ShareDriver):
subnet = utils.cidr_to_netmask(network_info['cidr'])
vlantag = network_info['segmentation_id']
self._hp3par.create_fsip(ip, subnet, vlantag, self.fpg, self.vfs)
self._hpe3par.create_fsip(ip, subnet, vlantag, self.fpg, self.vfs)
return {
'share_server_name': network_info['server_id'],
@ -207,9 +222,9 @@ class HP3ParShareDriver(driver.ShareDriver):
def _teardown_server(self, server_details, security_services=None):
LOG.debug("begin _teardown_server with %s", server_details)
self._hp3par.remove_fsip(server_details.get('ip'),
server_details.get('fpg'),
server_details.get('vfs'))
self._hpe3par.remove_fsip(server_details.get('ip'),
server_details.get('fpg'),
server_details.get('vfs'))
def _get_share_ip(self, share_server):
return share_server['backend_details'].get('ip') if share_server else (
@ -261,7 +276,7 @@ class HP3ParShareDriver(driver.ShareDriver):
protocol = share['share_proto']
extra_specs = share_types.get_extra_specs_from_share(share)
path = self._hp3par.create_share(
path = self._hpe3par.create_share(
share['project_id'],
share['id'],
protocol,
@ -282,7 +297,7 @@ class HP3ParShareDriver(driver.ShareDriver):
protocol = share['share_proto']
extra_specs = share_types.get_extra_specs_from_share(share)
path = self._hp3par.create_share_from_snapshot(
path = self._hpe3par.create_share_from_snapshot(
share['id'],
protocol,
extra_specs,
@ -300,38 +315,48 @@ class HP3ParShareDriver(driver.ShareDriver):
def delete_share(self, context, share, share_server=None):
"""Deletes share and its fstore."""
self._hp3par.delete_share(share['project_id'],
share['id'],
share['share_proto'],
self.fpg,
self.vfs)
self._hpe3par.delete_share(share['project_id'],
share['id'],
share['share_proto'],
self.fpg,
self.vfs)
def create_snapshot(self, context, snapshot, share_server=None):
"""Creates a snapshot of a share."""
self._hp3par.create_snapshot(snapshot['share']['project_id'],
snapshot['share']['id'],
snapshot['share']['share_proto'],
snapshot['id'],
self.fpg,
self.vfs)
self._hpe3par.create_snapshot(snapshot['share']['project_id'],
snapshot['share']['id'],
snapshot['share']['share_proto'],
snapshot['id'],
self.fpg,
self.vfs)
def delete_snapshot(self, context, snapshot, share_server=None):
"""Deletes a snapshot of a share."""
self._hp3par.delete_snapshot(snapshot['share']['project_id'],
snapshot['share']['id'],
snapshot['share']['share_proto'],
snapshot['id'],
self.fpg,
self.vfs)
self._hpe3par.delete_snapshot(snapshot['share']['project_id'],
snapshot['share']['id'],
snapshot['share']['share_proto'],
snapshot['id'],
self.fpg,
self.vfs)
def ensure_share(self, context, share, share_server=None):
pass
def allow_access(self, context, share, access, share_server=None):
"""Allow access to the share."""
self._hp3par.allow_access(share['project_id'],
self._hpe3par.allow_access(share['project_id'],
share['id'],
share['share_proto'],
access['access_type'],
access['access_to'],
self.fpg,
self.vfs)
def deny_access(self, context, share, access, share_server=None):
"""Deny access to the share."""
self._hpe3par.deny_access(share['project_id'],
share['id'],
share['share_proto'],
access['access_type'],
@ -339,21 +364,11 @@ class HP3ParShareDriver(driver.ShareDriver):
self.fpg,
self.vfs)
def deny_access(self, context, share, access, share_server=None):
"""Deny access to the share."""
self._hp3par.deny_access(share['project_id'],
share['id'],
share['share_proto'],
access['access_type'],
access['access_to'],
self.fpg,
self.vfs)
def _update_share_stats(self):
"""Retrieve stats info from share group."""
backend_name = self.configuration.safe_get(
'share_backend_name') or "HP_3PAR"
'share_backend_name') or "HPE_3PAR"
max_over_subscription_ratio = self.configuration.safe_get(
'max_over_subscription_ratio')
@ -366,7 +381,7 @@ class HP3ParShareDriver(driver.ShareDriver):
stats = {
'share_backend_name': backend_name,
'driver_handles_share_servers': self.driver_handles_share_servers,
'vendor_name': 'HP',
'vendor_name': 'HPE',
'driver_version': self.VERSION,
'storage_protocol': 'NFS_CIFS',
'total_capacity_gb': 0,
@ -378,13 +393,13 @@ class HP3ParShareDriver(driver.ShareDriver):
'thin_provisioning': True, # 3PAR default is thin
}
if not self._hp3par:
if not self._hpe3par:
LOG.info(
_LI("Skipping capacity and capabilities update. Setup has not "
"completed."))
else:
fpg_status = self._hp3par.get_fpg_status(self.fpg)
fpg_status = self._hpe3par.get_fpg_status(self.fpg)
LOG.debug("FPG status = %s.", fpg_status)
stats.update(fpg_status)
super(HP3ParShareDriver, self)._update_share_stats(stats)
super(HPE3ParShareDriver, self)._update_share_stats(stats)

View File

@ -1,4 +1,4 @@
# Copyright 2015 Hewlett Packard Development Company, L.P.
# Copyright 2015 Hewlett Packard Enterprise Development LP
#
# 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
@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
"""HP 3PAR Mediator for OpenStack Manila.
"""HPE 3PAR Mediator for OpenStack Manila.
This 'mediator' de-couples the 3PAR focused client from the OpenStack focused
driver.
@ -26,14 +26,13 @@ import six
from manila import exception
from manila.i18n import _, _LI, _LW
hp3parclient = importutils.try_import("hp3parclient")
if hp3parclient:
from hp3parclient import file_client
hpe3parclient = importutils.try_import("hpe3parclient")
if hpe3parclient:
from hpe3parclient import file_client
LOG = log.getLogger(__name__)
MIN_CLIENT_VERSION = (3, 2, 1)
MIN_SMB_CA_VERSION = (3, 2, 2)
MIN_CLIENT_VERSION = (4, 0, 0)
DENY = '-'
ALLOW = '+'
OPEN_STACK_MANILA = 'OpenStack Manila'
@ -52,31 +51,32 @@ SMB_EXTRA_SPECS_MAP = {
}
class HP3ParMediator(object):
class HPE3ParMediator(object):
"""3PAR client-facing code for the 3PAR driver.
Version history:
1.0.00 - Begin Liberty development (post-Kilo)
1.0.01 - Report thin/dedup/hp_flash_cache capabilities
1.0.02 - Add share server/share network support
1.0.03 - Use hp3par prefix for share types and capabilities
1.0.0 - Begin Liberty development (post-Kilo)
1.0.1 - Report thin/dedup/hp_flash_cache capabilities
1.0.2 - Add share server/share network support
1.0.3 - Use hp3par prefix for share types and capabilities
2.0.0 - Rebranded HP to HPE
"""
VERSION = "1.0.03"
VERSION = "2.0.0"
def __init__(self, **kwargs):
self.hp3par_username = kwargs.get('hp3par_username')
self.hp3par_password = kwargs.get('hp3par_password')
self.hp3par_api_url = kwargs.get('hp3par_api_url')
self.hp3par_debug = kwargs.get('hp3par_debug')
self.hp3par_san_ip = kwargs.get('hp3par_san_ip')
self.hp3par_san_login = kwargs.get('hp3par_san_login')
self.hp3par_san_password = kwargs.get('hp3par_san_password')
self.hp3par_san_ssh_port = kwargs.get('hp3par_san_ssh_port')
self.hp3par_san_private_key = kwargs.get('hp3par_san_private_key')
self.hp3par_fstore_per_share = kwargs.get('hp3par_fstore_per_share')
self.hpe3par_username = kwargs.get('hpe3par_username')
self.hpe3par_password = kwargs.get('hpe3par_password')
self.hpe3par_api_url = kwargs.get('hpe3par_api_url')
self.hpe3par_debug = kwargs.get('hpe3par_debug')
self.hpe3par_san_ip = kwargs.get('hpe3par_san_ip')
self.hpe3par_san_login = kwargs.get('hpe3par_san_login')
self.hpe3par_san_password = kwargs.get('hpe3par_san_password')
self.hpe3par_san_ssh_port = kwargs.get('hpe3par_san_ssh_port')
self.hpe3par_san_private_key = kwargs.get('hpe3par_san_private_key')
self.hpe3par_fstore_per_share = kwargs.get('hpe3par_fstore_per_share')
self.ssh_conn_timeout = kwargs.get('ssh_conn_timeout')
self._client = None
@ -84,61 +84,61 @@ class HP3ParMediator(object):
@staticmethod
def no_client():
return hp3parclient is None
return hpe3parclient is None
def do_setup(self):
if self.no_client():
msg = _('You must install hp3parclient before using the 3PAR '
msg = _('You must install hpe3parclient before using the 3PAR '
'driver.')
LOG.error(msg)
raise exception.HP3ParInvalidClient(message=msg)
raise exception.HPE3ParInvalidClient(message=msg)
self.client_version = hp3parclient.version_tuple
self.client_version = hpe3parclient.version_tuple
if self.client_version < MIN_CLIENT_VERSION:
msg = (_('Invalid hp3parclient version found (%(found)s). '
msg = (_('Invalid hpe3parclient version found (%(found)s). '
'Version %(minimum)s or greater required.') %
{'found': '.'.join(map(six.text_type, self.client_version)),
'minimum': '.'.join(map(six.text_type,
MIN_CLIENT_VERSION))})
LOG.error(msg)
raise exception.HP3ParInvalidClient(message=msg)
raise exception.HPE3ParInvalidClient(message=msg)
try:
self._client = file_client.HP3ParFilePersonaClient(
self.hp3par_api_url)
self._client = file_client.HPE3ParFilePersonaClient(
self.hpe3par_api_url)
except Exception as e:
msg = (_('Failed to connect to HP 3PAR File Persona Client: %s') %
msg = (_('Failed to connect to HPE 3PAR File Persona Client: %s') %
six.text_type(e))
LOG.exception(msg)
raise exception.ShareBackendException(message=msg)
try:
ssh_kwargs = {}
if self.hp3par_san_ssh_port:
ssh_kwargs['port'] = self.hp3par_san_ssh_port
if self.hpe3par_san_ssh_port:
ssh_kwargs['port'] = self.hpe3par_san_ssh_port
if self.ssh_conn_timeout:
ssh_kwargs['conn_timeout'] = self.ssh_conn_timeout
if self.hp3par_san_private_key:
ssh_kwargs['privatekey'] = self.hp3par_san_private_key
if self.hpe3par_san_private_key:
ssh_kwargs['privatekey'] = self.hpe3par_san_private_key
self._client.setSSHOptions(
self.hp3par_san_ip,
self.hp3par_san_login,
self.hp3par_san_password,
self.hpe3par_san_ip,
self.hpe3par_san_login,
self.hpe3par_san_password,
**ssh_kwargs
)
except Exception as e:
msg = (_('Failed to set SSH options for HP 3PAR File Persona '
msg = (_('Failed to set SSH options for HPE 3PAR File Persona '
'Client: %s') % six.text_type(e))
LOG.exception(msg)
raise exception.ShareBackendException(message=msg)
LOG.info(_LI("HP3ParMediator %(version)s, "
"hp3parclient %(client_version)s"),
LOG.info(_LI("HPE3ParMediator %(version)s, "
"hpe3parclient %(client_version)s"),
{"version": self.VERSION,
"client_version": hp3parclient.get_version_string()})
"client_version": hpe3parclient.get_version_string()})
try:
wsapi_version = self._client.getWsApiVersion()['build']
@ -149,17 +149,17 @@ class HP3ParMediator(object):
LOG.exception(msg)
raise exception.ShareBackendException(message=msg)
if self.hp3par_debug:
if self.hpe3par_debug:
self._client.debug_rest(True) # Includes SSH debug (setSSH above)
def _wsapi_login(self):
try:
self._client.login(self.hp3par_username, self.hp3par_password)
self._client.login(self.hpe3par_username, self.hpe3par_password)
except Exception as e:
msg = (_("Failed to Login to 3PAR (%(url)s) as %(user)s "
"because: %(err)s") %
{'url': self.hp3par_api_url,
'user': self.hp3par_username,
{'url': self.hpe3par_api_url,
'user': self.hpe3par_username,
'err': six.text_type(e)})
LOG.error(msg)
raise exception.ShareBackendException(msg=msg)
@ -169,7 +169,7 @@ class HP3ParMediator(object):
self._client.http.unauthenticate()
except Exception as e:
msg = _LW("Failed to Logout from 3PAR (%(url)s) because %(err)s")
LOG.warning(msg, {'url': self.hp3par_api_url,
LOG.warning(msg, {'url': self.hpe3par_api_url,
'err': six.text_type(e)})
# don't raise exception on logout()
@ -236,14 +236,15 @@ class HP3ParMediator(object):
thin_provisioning = provisioning_type in (THIN, DEDUPE)
flash_cache_policy = volume_set.get('flashCachePolicy', DISABLED)
hp3par_flash_cache = flash_cache_policy == ENABLED
hpe3par_flash_cache = flash_cache_policy == ENABLED
status = {
'total_capacity_gb': total_capacity_gb,
'free_capacity_gb': free_capacity_gb,
'thin_provisioning': thin_provisioning,
'dedupe': dedupe,
'hp3par_flash_cache': hp3par_flash_cache,
'hpe3par_flash_cache': hpe3par_flash_cache,
'hp3par_flash_cache': hpe3par_flash_cache,
}
if thin_provisioning:
@ -266,7 +267,7 @@ class HP3ParMediator(object):
@staticmethod
def other_protocol(share_proto):
"""Given 'nfs' or 'smb' (or equivalent) return the other one."""
protocol = HP3ParMediator.ensure_supported_protocol(share_proto)
protocol = HPE3ParMediator.ensure_supported_protocol(share_proto)
return 'nfs' if protocol == 'smb' else 'smb'
@staticmethod
@ -275,7 +276,7 @@ class HP3ParMediator(object):
return uid
elif protocol:
return 'osf-%s-%s' % (
HP3ParMediator.ensure_supported_protocol(protocol), uid)
HPE3ParMediator.ensure_supported_protocol(protocol), uid)
else:
return 'osf-%s' % uid
@ -283,7 +284,14 @@ class HP3ParMediator(object):
def _get_nfs_options(extra_specs, readonly):
"""Validate the NFS extra_specs and return the options to use."""
nfs_options = extra_specs.get('hp3par:nfs_options')
nfs_options = extra_specs.get('hpe3par:nfs_options')
if nfs_options is None:
nfs_options = extra_specs.get('hp3par:nfs_options')
if nfs_options:
msg = _LW("hp3par:nfs_options is deprecated. Use "
"hpe3par:nfs_options instead.")
LOG.warning(msg)
if nfs_options:
options = nfs_options.split(',')
else:
@ -304,7 +312,8 @@ class HP3ParMediator(object):
]
if invalid_options:
raise exception.InvalidInput(_('Invalid hp3par:nfs_options in '
raise exception.InvalidInput(_('Invalid hp3par:nfs_options or '
'hpe3par:nfs_options in '
'extra-specs. The following '
'options are not allowed: %s') %
invalid_options)
@ -321,6 +330,12 @@ class HP3ParMediator(object):
fstore=fstore,
sharedir=sharedir,
comment=comment)
if 'hp3par_flash_cache' in extra_specs:
msg = _LW("hp3par_flash_cache is deprecated. Use "
"hpe3par_flash_cache instead.")
LOG.warning(msg)
if protocol == 'nfs':
createfshare_kwargs['clientip'] = '127.0.0.1'
options = self._get_nfs_options(extra_specs, readonly)
@ -328,13 +343,17 @@ class HP3ParMediator(object):
else:
createfshare_kwargs['allowip'] = '127.0.0.1'
if self.client_version < MIN_SMB_CA_VERSION:
smb_opts = (ACCESS_BASED_ENUM, CACHE)
else:
smb_opts = (ACCESS_BASED_ENUM, CONTINUOUS_AVAIL, CACHE)
smb_opts = (ACCESS_BASED_ENUM, CONTINUOUS_AVAIL, CACHE)
for smb_opt in smb_opts:
opt_value = extra_specs.get('hp3par:smb_%s' % smb_opt)
opt_value = extra_specs.get('hpe3par:smb_%s' % smb_opt)
if opt_value is None:
opt_value = extra_specs.get('hp3par:smb_%s' % smb_opt)
if opt_value:
msg = _LW("hp3par:smb_* is deprecated. Use "
"hpe3par:smb_* instead.")
LOG.warning(msg)
if opt_value:
opt_key = SMB_EXTRA_SPECS_MAP[smb_opt]
createfshare_kwargs[opt_key] = opt_value
@ -367,14 +386,14 @@ class HP3ParMediator(object):
protocol = self.ensure_supported_protocol(share_proto)
share_name = self.ensure_prefix(share_id)
if not (sharedir or self.hp3par_fstore_per_share):
if not (sharedir or self.hpe3par_fstore_per_share):
sharedir = share_name
if fstore:
use_existing_fstore = True
else:
use_existing_fstore = False
if self.hp3par_fstore_per_share:
if self.hpe3par_fstore_per_share:
fstore = share_name
else:
fstore = self.ensure_prefix(project_id, protocol)
@ -401,7 +420,7 @@ class HP3ParMediator(object):
raise exception.ShareBackendException(msg)
if size:
if self.hp3par_fstore_per_share:
if self.hpe3par_fstore_per_share:
hcapacity = six.text_type(size * units.Ki)
scapacity = hcapacity
else:
@ -706,10 +725,10 @@ class HP3ParMediator(object):
raise exception.InvalidInput(msg)
if protocol == 'nfs' and access_type != 'ip':
msg = (_("Invalid NFS access type. HP 3PAR NFS supports 'ip'. "
msg = (_("Invalid NFS access type. HPE 3PAR NFS supports 'ip'. "
"Actual '%s'.") % access_type)
LOG.error(msg)
raise exception.HP3ParInvalid(msg)
raise exception.HPE3ParInvalid(msg)
return protocol
@ -748,7 +767,7 @@ class HP3ParMediator(object):
msg = (_("Unexpected error: After ensure_supported_protocol "
"only 'nfs' or 'smb' strings are allowed, but found: "
"%s.") % protocol)
raise exception.HP3ParUnexpectedError(msg)
raise exception.HPE3ParUnexpectedError(msg)
LOG.debug("setfshare result=%s", result)
except Exception as e:

View File

@ -98,7 +98,10 @@ CONF.import_opt('periodic_hooks_interval', 'manila.share.hook')
# old/new path here to maintain backward compatibility.
MAPPING = {
'manila.share.drivers.netapp.cluster_mode.NetAppClusteredShareDriver':
'manila.share.drivers.netapp.common.NetAppDriver', }
'manila.share.drivers.netapp.common.NetAppDriver',
'manila.share.drivers.hp.hp_3par_driver.HP3ParShareDriver':
'manila.share.drivers.hpe.hpe_3par_driver.HPE3ParShareDriver',
}
QUOTAS = quota.QUOTAS

View File

@ -1,4 +1,4 @@
# Copyright 2015 Hewlett Packard Development Company, L.P.
# Copyright 2015 Hewlett Packard Enterprise Development LP
#
# 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
@ -48,7 +48,7 @@ EXPECTED_STATS = {'test': 'stats'}
EXPECTED_FPG = 'FPG_1'
EXPECTED_FSTORE = EXPECTED_PROJECT_ID
EXPECTED_VFS = 'test_vfs'
EXPECTED_HP_DEBUG = True
EXPECTED_HPE_DEBUG = True
EXPECTED_EXTRA_SPECS = {}
GET_FSQUOTA = {'message': None,

View File

@ -1,4 +1,4 @@
# Copyright 2015 Hewlett Packard Development Company, L.P.
# Copyright 2015 Hewlett Packard Enterprise Development LP
#
# 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
@ -16,37 +16,37 @@ import sys
import ddt
import mock
if 'hp3parclient' not in sys.modules:
sys.modules['hp3parclient'] = mock.Mock()
if 'hpe3parclient' not in sys.modules:
sys.modules['hpe3parclient'] = mock.Mock()
from manila import exception
from manila.share.drivers.hp import hp_3par_driver as hp3pardriver
from manila.share.drivers.hp import hp_3par_mediator as hp3parmediator
from manila.share.drivers.hpe import hpe_3par_driver as hpe3pardriver
from manila.share.drivers.hpe import hpe_3par_mediator as hpe3parmediator
from manila import test
from manila.tests.share.drivers.hp import test_hp_3par_constants as constants
from manila.tests.share.drivers.hpe import test_hpe_3par_constants as constants
@ddt.ddt
class HP3ParDriverTestCase(test.TestCase):
class HPE3ParDriverTestCase(test.TestCase):
def setUp(self):
super(HP3ParDriverTestCase, self).setUp()
super(HPE3ParDriverTestCase, self).setUp()
# Create a mock configuration with attributes and a safe_get()
self.conf = mock.Mock()
self.conf.driver_handles_share_servers = True
self.conf.hp3par_debug = constants.EXPECTED_HP_DEBUG
self.conf.hp3par_username = constants.USERNAME
self.conf.hp3par_password = constants.PASSWORD
self.conf.hp3par_api_url = constants.API_URL
self.conf.hp3par_san_login = constants.SAN_LOGIN
self.conf.hp3par_san_password = constants.SAN_PASSWORD
self.conf.hp3par_san_ip = constants.EXPECTED_IP_1234
self.conf.hp3par_fpg = constants.EXPECTED_FPG
self.conf.hp3par_san_ssh_port = constants.PORT
self.conf.hpe3par_debug = constants.EXPECTED_HPE_DEBUG
self.conf.hpe3par_username = constants.USERNAME
self.conf.hpe3par_password = constants.PASSWORD
self.conf.hpe3par_api_url = constants.API_URL
self.conf.hpe3par_san_login = constants.SAN_LOGIN
self.conf.hpe3par_san_password = constants.SAN_PASSWORD
self.conf.hpe3par_san_ip = constants.EXPECTED_IP_1234
self.conf.hpe3par_fpg = constants.EXPECTED_FPG
self.conf.hpe3par_san_ssh_port = constants.PORT
self.conf.ssh_conn_timeout = constants.TIMEOUT
self.conf.hp3par_share_ip_address = None
self.conf.hp3par_fstore_per_share = False
self.conf.hpe3par_share_ip_address = None
self.conf.hpe3par_fstore_per_share = False
self.conf.network_config_group = 'test_network_config_group'
def safe_get(attr):
@ -56,12 +56,12 @@ class HP3ParDriverTestCase(test.TestCase):
return None
self.conf.safe_get = safe_get
self.real_hp_3par_mediator = hp3parmediator.HP3ParMediator
self.mock_object(hp3parmediator, 'HP3ParMediator')
self.mock_mediator_constructor = hp3parmediator.HP3ParMediator
self.real_hpe_3par_mediator = hpe3parmediator.HPE3ParMediator
self.mock_object(hpe3parmediator, 'HPE3ParMediator')
self.mock_mediator_constructor = hpe3parmediator.HPE3ParMediator
self.mock_mediator = self.mock_mediator_constructor()
self.driver = hp3pardriver.HP3ParShareDriver(
self.driver = hpe3pardriver.HPE3ParShareDriver(
configuration=self.conf)
def test_driver_setup_success(self):
@ -72,20 +72,20 @@ class HP3ParDriverTestCase(test.TestCase):
self.driver.do_setup(None)
conf = self.conf
self.mock_mediator_constructor.assert_has_calls([
mock.call(hp3par_san_ssh_port=conf.hp3par_san_ssh_port,
hp3par_san_password=conf.hp3par_san_password,
hp3par_username=conf.hp3par_username,
hp3par_san_login=conf.hp3par_san_login,
hp3par_debug=conf.hp3par_debug,
hp3par_api_url=conf.hp3par_api_url,
hp3par_password=conf.hp3par_password,
hp3par_san_ip=conf.hp3par_san_ip,
hp3par_fstore_per_share=conf.hp3par_fstore_per_share,
mock.call(hpe3par_san_ssh_port=conf.hpe3par_san_ssh_port,
hpe3par_san_password=conf.hpe3par_san_password,
hpe3par_username=conf.hpe3par_username,
hpe3par_san_login=conf.hpe3par_san_login,
hpe3par_debug=conf.hpe3par_debug,
hpe3par_api_url=conf.hpe3par_api_url,
hpe3par_password=conf.hpe3par_password,
hpe3par_san_ip=conf.hpe3par_san_ip,
hpe3par_fstore_per_share=conf.hpe3par_fstore_per_share,
ssh_conn_timeout=conf.ssh_conn_timeout)])
self.mock_mediator.assert_has_calls([
mock.call.do_setup(),
mock.call.get_vfs_name(conf.hp3par_fpg)])
mock.call.get_vfs_name(conf.hpe3par_fpg)])
self.assertEqual(constants.EXPECTED_VFS, self.driver.vfs)
@ -93,7 +93,7 @@ class HP3ParDriverTestCase(test.TestCase):
"""Driver do_setup without any errors with dhss=False."""
self.conf.driver_handles_share_servers = False
self.conf.hp3par_share_ip_address = constants.EXPECTED_IP_10203040
self.conf.hpe3par_share_ip_address = constants.EXPECTED_IP_10203040
self.test_driver_setup_success()
@ -101,7 +101,7 @@ class HP3ParDriverTestCase(test.TestCase):
"""Configured IP address is required for dhss=False."""
self.conf.driver_handles_share_servers = False
self.assertRaises(exception.HP3ParInvalid,
self.assertRaises(exception.HPE3ParInvalid,
self.driver.do_setup, None)
def test_driver_with_setup_error(self):
@ -115,15 +115,15 @@ class HP3ParDriverTestCase(test.TestCase):
conf = self.conf
self.mock_mediator_constructor.assert_has_calls([
mock.call(hp3par_san_ssh_port=conf.hp3par_san_ssh_port,
hp3par_san_password=conf.hp3par_san_password,
hp3par_username=conf.hp3par_username,
hp3par_san_login=conf.hp3par_san_login,
hp3par_debug=conf.hp3par_debug,
hp3par_api_url=conf.hp3par_api_url,
hp3par_password=conf.hp3par_password,
hp3par_san_ip=conf.hp3par_san_ip,
hp3par_fstore_per_share=conf.hp3par_fstore_per_share,
mock.call(hpe3par_san_ssh_port=conf.hpe3par_san_ssh_port,
hpe3par_san_password=conf.hpe3par_san_password,
hpe3par_username=conf.hpe3par_username,
hpe3par_san_login=conf.hpe3par_san_login,
hpe3par_debug=conf.hpe3par_debug,
hpe3par_api_url=conf.hpe3par_api_url,
hpe3par_password=conf.hpe3par_password,
hpe3par_san_ip=conf.hpe3par_san_ip,
hpe3par_fstore_per_share=conf.hpe3par_fstore_per_share,
ssh_conn_timeout=conf.ssh_conn_timeout)])
self.mock_mediator.assert_has_calls([mock.call.do_setup()])
@ -139,29 +139,29 @@ class HP3ParDriverTestCase(test.TestCase):
conf = self.conf
self.mock_mediator_constructor.assert_has_calls([
mock.call(hp3par_san_ssh_port=conf.hp3par_san_ssh_port,
hp3par_san_password=conf.hp3par_san_password,
hp3par_username=conf.hp3par_username,
hp3par_san_login=conf.hp3par_san_login,
hp3par_debug=conf.hp3par_debug,
hp3par_api_url=conf.hp3par_api_url,
hp3par_password=conf.hp3par_password,
hp3par_san_ip=conf.hp3par_san_ip,
hp3par_fstore_per_share=conf.hp3par_fstore_per_share,
mock.call(hpe3par_san_ssh_port=conf.hpe3par_san_ssh_port,
hpe3par_san_password=conf.hpe3par_san_password,
hpe3par_username=conf.hpe3par_username,
hpe3par_san_login=conf.hpe3par_san_login,
hpe3par_debug=conf.hpe3par_debug,
hpe3par_api_url=conf.hpe3par_api_url,
hpe3par_password=conf.hpe3par_password,
hpe3par_san_ip=conf.hpe3par_san_ip,
hpe3par_fstore_per_share=conf.hpe3par_fstore_per_share,
ssh_conn_timeout=conf.ssh_conn_timeout)])
self.mock_mediator.assert_has_calls([
mock.call.do_setup(),
mock.call.get_vfs_name(conf.hp3par_fpg)])
mock.call.get_vfs_name(conf.hpe3par_fpg)])
def init_driver(self):
"""Simple driver setup for re-use with tests that need one."""
self.driver._hp3par = self.mock_mediator
self.driver._hpe3par = self.mock_mediator
self.driver.vfs = constants.EXPECTED_VFS
self.driver.fpg = constants.EXPECTED_FPG
self.mock_object(hp3pardriver, 'share_types')
get_extra_specs = hp3pardriver.share_types.get_extra_specs_from_share
self.mock_object(hpe3pardriver, 'share_types')
get_extra_specs = hpe3pardriver.share_types.get_extra_specs_from_share
get_extra_specs.return_value = constants.EXPECTED_EXTRA_SPECS
def do_create_share(self, protocol, share_type_id, expected_project_id,
@ -213,29 +213,29 @@ class HP3ParDriverTestCase(test.TestCase):
"""check_for_setup_error when things go well."""
# Generally this is always mocked, but here we reference the class.
hp3parmediator.HP3ParMediator = self.real_hp_3par_mediator
hpe3parmediator.HPE3ParMediator = self.real_hpe_3par_mediator
self.mock_object(hp3pardriver, 'LOG')
self.mock_object(hpe3pardriver, 'LOG')
self.init_driver()
self.driver.check_for_setup_error()
expected_calls = [
mock.call.debug('HP3ParShareDriver SHA1: %s', mock.ANY),
mock.call.debug('HP3ParMediator SHA1: %s', mock.ANY)
mock.call.debug('HPE3ParShareDriver SHA1: %s', mock.ANY),
mock.call.debug('HPE3ParMediator SHA1: %s', mock.ANY)
]
hp3pardriver.LOG.assert_has_calls(expected_calls)
hpe3pardriver.LOG.assert_has_calls(expected_calls)
def test_driver_check_for_setup_error_exception(self):
"""check_for_setup_error catch and log any exceptions."""
# Since HP3ParMediator is mocked, we'll hit the except/log.
self.mock_object(hp3pardriver, 'LOG')
# Since HPE3ParMediator is mocked, we'll hit the except/log.
self.mock_object(hpe3pardriver, 'LOG')
self.init_driver()
self.driver.check_for_setup_error()
expected_calls = [
mock.call.debug('HP3ParShareDriver SHA1: %s', mock.ANY),
mock.call.debug('HPE3ParShareDriver SHA1: %s', mock.ANY),
mock.call.debug('Source code SHA1 not logged due to: %s', mock.ANY)
]
hp3pardriver.LOG.assert_has_calls(expected_calls)
hpe3pardriver.LOG.assert_has_calls(expected_calls)
def test_driver_create_cifs_share(self):
self.init_driver()
@ -458,7 +458,7 @@ class HP3ParDriverTestCase(test.TestCase):
def test_driver_get_share_stats_not_ready(self):
"""Protect against stats update before driver is ready."""
self.mock_object(hp3pardriver, 'LOG')
self.mock_object(hpe3pardriver, 'LOG')
expected_result = {
'driver_handles_share_servers': True,
@ -468,12 +468,12 @@ class HP3ParDriverTestCase(test.TestCase):
'max_over_subscription_ratio': None,
'reserved_percentage': 0,
'provisioned_capacity_gb': 0,
'share_backend_name': 'HP_3PAR',
'share_backend_name': 'HPE_3PAR',
'snapshot_support': True,
'storage_protocol': 'NFS_CIFS',
'thin_provisioning': True,
'total_capacity_gb': 0,
'vendor_name': 'HP',
'vendor_name': 'HPE',
'pools': None,
}
@ -484,7 +484,7 @@ class HP3ParDriverTestCase(test.TestCase):
mock.call.info('Skipping capacity and capabilities update. '
'Setup has not completed.')
]
hp3pardriver.LOG.assert_has_calls(expected_calls)
hpe3pardriver.LOG.assert_has_calls(expected_calls)
def test_driver_get_share_stats_no_refresh(self):
"""Driver does not call mediator when refresh=False."""
@ -511,6 +511,7 @@ class HP3ParDriverTestCase(test.TestCase):
'thin_provisioning': True,
'dedupe': False,
'hpe3par_flash_cache': False,
'hp3par_flash_cache': False,
}
expected_result = {
@ -522,13 +523,14 @@ class HP3ParDriverTestCase(test.TestCase):
'pools': None,
'provisioned_capacity_gb': 0,
'reserved_percentage': 0,
'share_backend_name': 'HP_3PAR',
'share_backend_name': 'HPE_3PAR',
'storage_protocol': 'NFS_CIFS',
'total_capacity_gb': expected_capacity,
'vendor_name': 'HP',
'vendor_name': 'HPE',
'thin_provisioning': True,
'dedupe': False,
'hpe3par_flash_cache': False,
'hp3par_flash_cache': False,
'snapshot_support': True,
}
@ -557,11 +559,11 @@ class HP3ParDriverTestCase(test.TestCase):
'pools': None,
'provisioned_capacity_gb': 0,
'reserved_percentage': 0,
'share_backend_name': 'HP_3PAR',
'share_backend_name': 'HPE_3PAR',
'storage_protocol': 'NFS_CIFS',
'thin_provisioning': True,
'total_capacity_gb': 0,
'vendor_name': 'HP',
'vendor_name': 'HPE',
'snapshot_support': True,
}

View File

@ -1,4 +1,4 @@
# Copyright 2015 Hewlett Packard Development Company, L.P.
# Copyright 2015 Hewlett Packard Enterprise Development LP
#
# 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
@ -16,60 +16,60 @@ import sys
import ddt
import mock
if 'hp3parclient' not in sys.modules:
sys.modules['hp3parclient'] = mock.Mock()
if 'hpe3parclient' not in sys.modules:
sys.modules['hpe3parclient'] = mock.Mock()
from manila import exception
from manila.share.drivers.hp import hp_3par_mediator as hp3parmediator
from manila.share.drivers.hpe import hpe_3par_mediator as hpe3parmediator
from manila import test
from manila.tests.share.drivers.hp import test_hp_3par_constants as constants
from manila.tests.share.drivers.hpe import test_hpe_3par_constants as constants
from oslo_utils import units
import six
CLIENT_VERSION_MIN_OK = hp3parmediator.MIN_CLIENT_VERSION
CLIENT_VERSION_MIN_OK = hpe3parmediator.MIN_CLIENT_VERSION
TEST_WSAPI_VERSION_STR = '30201292'
@ddt.ddt
class HP3ParMediatorTestCase(test.TestCase):
class HPE3ParMediatorTestCase(test.TestCase):
def setUp(self):
super(HP3ParMediatorTestCase, self).setUp()
super(HPE3ParMediatorTestCase, self).setUp()
# This is the fake client to use.
self.mock_client = mock.Mock()
# Take over the hp3parclient module and stub the constructor.
hp3parclient = sys.modules['hp3parclient']
hp3parclient.version_tuple = CLIENT_VERSION_MIN_OK
# Take over the hpe3parclient module and stub the constructor.
hpe3parclient = sys.modules['hpe3parclient']
hpe3parclient.version_tuple = CLIENT_VERSION_MIN_OK
# Need a fake constructor to return the fake client.
# This is also be used for constructor error tests.
self.mock_object(hp3parclient.file_client, 'HP3ParFilePersonaClient')
self.mock_object(hpe3parclient.file_client, 'HPE3ParFilePersonaClient')
self.mock_client_constructor = (
hp3parclient.file_client.HP3ParFilePersonaClient
hpe3parclient.file_client.HPE3ParFilePersonaClient
)
self.mock_client = self.mock_client_constructor()
# Set the mediator to use in tests.
self.mediator = hp3parmediator.HP3ParMediator(
hp3par_username=constants.USERNAME,
hp3par_password=constants.PASSWORD,
hp3par_api_url=constants.API_URL,
hp3par_debug=constants.EXPECTED_HP_DEBUG,
hp3par_san_ip=constants.EXPECTED_IP_1234,
hp3par_san_login=constants.SAN_LOGIN,
hp3par_san_password=constants.SAN_PASSWORD,
hp3par_san_ssh_port=constants.PORT,
self.mediator = hpe3parmediator.HPE3ParMediator(
hpe3par_username=constants.USERNAME,
hpe3par_password=constants.PASSWORD,
hpe3par_api_url=constants.API_URL,
hpe3par_debug=constants.EXPECTED_HPE_DEBUG,
hpe3par_san_ip=constants.EXPECTED_IP_1234,
hpe3par_san_login=constants.SAN_LOGIN,
hpe3par_san_password=constants.SAN_PASSWORD,
hpe3par_san_ssh_port=constants.PORT,
ssh_conn_timeout=constants.TIMEOUT)
def test_mediator_no_client(self):
"""Test missing hp3parclient error."""
"""Test missing hpe3parclient error."""
self.mock_object(hp3parmediator.HP3ParMediator, 'no_client', None)
self.mock_object(hpe3parmediator.HPE3ParMediator, 'no_client', None)
self.assertRaises(exception.HP3ParInvalidClient,
self.assertRaises(exception.HPE3ParInvalidClient,
self.mediator.do_setup)
def test_mediator_setup_client_init_error(self):
@ -154,7 +154,7 @@ class HP3ParMediatorTestCase(test.TestCase):
port=constants.PORT,
conn_timeout=constants.TIMEOUT),
mock.call.getWsApiVersion(),
mock.call.debug_rest(constants.EXPECTED_HP_DEBUG)
mock.call.debug_rest(constants.EXPECTED_HPE_DEBUG)
]
self.mock_client.assert_has_calls(expected_calls)
@ -175,7 +175,7 @@ class HP3ParMediatorTestCase(test.TestCase):
"""Test exception during logout."""
self.init_mediator()
mock_log = self.mock_object(hp3parmediator, 'LOG')
mock_log = self.mock_object(hpe3parmediator, 'LOG')
fake_exception = constants.FAKE_EXCEPTION
self.mock_client.http.unauthenticate.side_effect = fake_exception
@ -189,21 +189,21 @@ class HP3ParMediatorTestCase(test.TestCase):
def test_mediator_client_version_unsupported(self):
"""Try a client with version less than minimum."""
self.hp3parclient = sys.modules['hp3parclient']
self.hp3parclient.version_tuple = (CLIENT_VERSION_MIN_OK[0],
CLIENT_VERSION_MIN_OK[1],
CLIENT_VERSION_MIN_OK[2] - 1)
self.assertRaises(exception.HP3ParInvalidClient,
self.hpe3parclient = sys.modules['hpe3parclient']
self.hpe3parclient.version_tuple = (CLIENT_VERSION_MIN_OK[0],
CLIENT_VERSION_MIN_OK[1],
CLIENT_VERSION_MIN_OK[2] - 1)
self.assertRaises(exception.HPE3ParInvalidClient,
self.init_mediator)
def test_mediator_client_version_supported(self):
"""Try a client with a version greater than the minimum."""
# The setup success already tests the min version. Try version > min.
self.hp3parclient = sys.modules['hp3parclient']
self.hp3parclient.version_tuple = (CLIENT_VERSION_MIN_OK[0],
CLIENT_VERSION_MIN_OK[1],
CLIENT_VERSION_MIN_OK[2] + 1)
self.hpe3parclient = sys.modules['hpe3parclient']
self.hpe3parclient.version_tuple = (CLIENT_VERSION_MIN_OK[0],
CLIENT_VERSION_MIN_OK[1],
CLIENT_VERSION_MIN_OK[2] + 1)
self.init_mediator()
expected_calls = [
mock.call.setSSHOptions(constants.EXPECTED_IP_1234,
@ -212,7 +212,7 @@ class HP3ParMediatorTestCase(test.TestCase):
port=constants.PORT,
conn_timeout=constants.TIMEOUT),
mock.call.getWsApiVersion(),
mock.call.debug_rest(constants.EXPECTED_HP_DEBUG)
mock.call.debug_rest(constants.EXPECTED_HPE_DEBUG)
]
self.mock_client.assert_has_calls(expected_calls)
@ -251,7 +251,7 @@ class HP3ParMediatorTestCase(test.TestCase):
createfshare_kwargs['clientip'] = '127.0.0.1'
# Options from extra-specs.
opt_string = extra_specs.get('hp3par:nfs_options', [])
opt_string = extra_specs.get('hpe3par:nfs_options', [])
opt_list = opt_string.split(',')
# Options that the mediator adds.
nfs_options = ['rw', 'no_root_squash', 'insecure']
@ -282,18 +282,14 @@ class HP3ParMediatorTestCase(test.TestCase):
else:
createfshare_kwargs['allowip'] = '127.0.0.1'
if client_version < hp3parmediator.MIN_SMB_CA_VERSION:
smb_opts = (hp3parmediator.ACCESS_BASED_ENUM,
hp3parmediator.CACHE)
else:
smb_opts = (hp3parmediator.ACCESS_BASED_ENUM,
hp3parmediator.CONTINUOUS_AVAIL,
hp3parmediator.CACHE)
smb_opts = (hpe3parmediator.ACCESS_BASED_ENUM,
hpe3parmediator.CONTINUOUS_AVAIL,
hpe3parmediator.CACHE)
for smb_opt in smb_opts:
opt_value = extra_specs.get('hp3par:smb_%s' % smb_opt)
opt_value = extra_specs.get('hpe3par:smb_%s' % smb_opt)
if opt_value:
opt_key = hp3parmediator.SMB_EXTRA_SPECS_MAP[smb_opt]
opt_key = hpe3parmediator.SMB_EXTRA_SPECS_MAP[smb_opt]
createfshare_kwargs[opt_key] = opt_value
expected_calls = [
@ -320,25 +316,19 @@ class HP3ParMediatorTestCase(test.TestCase):
def _build_smb_extra_specs(**kwargs):
extra_specs = {'driver_handles_share_servers': False}
for k, v in kwargs.items():
extra_specs['hp3par:smb_%s' % k] = v
extra_specs['hpe3par:smb_%s' % k] = v
return extra_specs
@ddt.data(((3, 2, 1), None, None, None),
((3, 2, 1), 'true', None, None),
((3, 2, 1), None, 'false', None),
((3, 2, 1), None, 'false', None),
((3, 2, 1), None, None, 'optimized'),
((3, 2, 1), 'true', 'false', 'optimized'),
((3, 2, 2), None, None, None),
((3, 2, 2), 'true', None, None),
((3, 2, 2), None, 'false', None),
((3, 2, 2), None, 'false', None),
((3, 2, 2), None, None, 'optimized'),
((3, 2, 2), 'true', 'false', 'optimized'))
@ddt.data(((4, 0, 0), None, None, None),
((4, 0, 0), 'true', None, None),
((4, 0, 0), None, 'false', None),
((4, 0, 0), None, 'false', None),
((4, 0, 0), None, None, 'optimized'),
((4, 0, 0), 'true', 'false', 'optimized'))
@ddt.unpack
def test_mediator_create_cifs_share(self, client_version, abe, ca, cache):
self.hp3parclient = sys.modules['hp3parclient']
self.hp3parclient.version_tuple = client_version
self.hpe3parclient = sys.modules['hpe3parclient']
self.hpe3parclient.version_tuple = client_version
self.init_mediator()
self.mock_client.getfshare.return_value = {
@ -384,7 +374,7 @@ class HP3ParMediatorTestCase(test.TestCase):
def test_mediator_create_nfs_share_bad_options(self, nfs_options):
self.init_mediator()
extra_specs = {'hp3par:nfs_options': nfs_options}
extra_specs = {'hpe3par:nfs_options': nfs_options}
self.assertRaises(exception.InvalidInput,
self.mediator.create_share,
@ -411,7 +401,7 @@ class HP3ParMediatorTestCase(test.TestCase):
self.mock_client.getfsquota.return_value = constants.GET_FSQUOTA
extra_specs = {'hp3par:nfs_options': nfs_options}
extra_specs = {'hpe3par:nfs_options': nfs_options}
location = self.mediator.create_share(constants.EXPECTED_PROJECT_ID,
constants.EXPECTED_SHARE_ID,
@ -424,7 +414,7 @@ class HP3ParMediatorTestCase(test.TestCase):
self.assertEqual(constants.EXPECTED_SHARE_PATH, location)
expected_calls = self.get_expected_calls_for_create_share(
hp3parmediator.MIN_CLIENT_VERSION,
hpe3parmediator.MIN_CLIENT_VERSION,
constants.EXPECTED_FPG,
constants.EXPECTED_VFS,
constants.NFS.lower(),
@ -853,7 +843,7 @@ class HP3ParMediatorTestCase(test.TestCase):
# startfsnapclean exception (logged, not raised)
self.mock_client.startfsnapclean.side_effect = Exception(
'startfsnapclean fail.')
mock_log = self.mock_object(hp3parmediator, 'LOG')
mock_log = self.mock_object(hpe3parmediator, 'LOG')
self.mediator.delete_snapshot(constants.EXPECTED_PROJECT_ID,
constants.EXPECTED_SHARE_ID,
@ -917,10 +907,11 @@ class HP3ParMediatorTestCase(test.TestCase):
}
self.mock_client.getVolume.return_value = {
'provisioningType': hp3parmediator.DEDUPE}
'provisioningType': hpe3parmediator.DEDUPE}
expected_result = {
'free_capacity_gb': expected_free,
'hpe3par_flash_cache': False,
'hp3par_flash_cache': False,
'dedupe': True,
'thin_provisioning': True,
@ -1163,7 +1154,7 @@ class HP3ParMediatorTestCase(test.TestCase):
""""Allow user access to nfs share is not supported."""
self.init_mediator()
self.assertRaises(exception.HP3ParInvalid,
self.assertRaises(exception.HPE3ParInvalid,
self.mediator.allow_access,
constants.EXPECTED_PROJECT_ID,
constants.EXPECTED_SHARE_ID,
@ -1207,13 +1198,13 @@ class HP3ParMediatorTestCase(test.TestCase):
def test_other_protocol(self, protocols, expected_other):
for protocol in protocols:
self.assertEqual(expected_other,
hp3parmediator.HP3ParMediator().other_protocol(
hpe3parmediator.HPE3ParMediator().other_protocol(
protocol))
@ddt.data('', 'bogus')
def test_other_protocol_exception(self, protocol):
self.assertRaises(exception.InvalidInput,
hp3parmediator.HP3ParMediator().other_protocol,
hpe3parmediator.HPE3ParMediator().other_protocol,
protocol)
@ddt.data(('osf-uid', None, 'osf-uid'),
@ -1223,7 +1214,7 @@ class HP3ParMediatorTestCase(test.TestCase):
@ddt.unpack
def test_ensure_prefix(self, uid, protocol, expected):
self.assertEqual(expected,
hp3parmediator.HP3ParMediator().ensure_prefix(
hpe3parmediator.HPE3ParMediator().ensure_prefix(
uid, protocol=protocol))
def test_find_fstore_search(self):