Skip to content

Commit

Permalink
Python 3parclient merlin support (#69)
Browse files Browse the repository at this point in the history
* Modified createvolume and copyvolume to support merlin

* Added UTs for the createvolume and copy volume for merlin

* resolved pep8 errors

* Resolved pep8 fixes

* Added condition to handle the junk string as invalid input

* modified same conditions for copyvolume method

* Modified merlin to primera in client.py and uts, added version and changelog
  • Loading branch information
bhagyashree-sarawate authored and HPE Storage committed Jul 15, 2019
1 parent de7c4a2 commit aad5522
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 4 deletions.
3 changes: 3 additions & 0 deletions docs/changelog.rst
@@ -1,5 +1,8 @@
Changelog
=========
Changes in Version 4.2.10
------------------------
* Added support for Primera array

Changes in Version 4.2.9
------------------------
Expand Down
2 changes: 1 addition & 1 deletion hpe3parclient/__init__.py
Expand Up @@ -22,7 +22,7 @@
"""

version_tuple = (4, 2, 9)
version_tuple = (4, 2, 10)


def get_version_string():
Expand Down
83 changes: 82 additions & 1 deletion hpe3parclient/client.py
Expand Up @@ -30,6 +30,7 @@
import re
import time
import uuid
import logging

try:
# For Python 3.0 and later
Expand All @@ -41,6 +42,8 @@
from hpe3parclient import exceptions, http, ssh
from hpe3parclient import showport_parser

logger = logging.getLogger(__name__)


class HPE3ParClient(object):
""" The 3PAR REST API Client.
Expand Down Expand Up @@ -127,6 +130,9 @@ class HPE3ParClient(object):
HPE3PAR_WS_MIN_BUILD_VERSION = 30103230
HPE3PAR_WS_MIN_BUILD_VERSION_DESC = '3.1.3 MU1'

HPE3PAR_WS_PRIMERA_MIN_BUILD_VERSION = 40000128
HPE3PAR_WS_PRIMERA_MIN_BUILD_VERSIONDESC = '4.2.0'

# Minimum build version needed for VLUN query support.
HPE3PAR_WS_MIN_BUILD_VERSION_VLUN_QUERY = 30201292
HPE3PAR_WS_MIN_BUILD_VERSION_VLUN_QUERY_DESC = '3.2.1 MU2'
Expand Down Expand Up @@ -196,6 +202,7 @@ def __init__(self, api_url, debug=False, secure=False, timeout=None,
api_version = None
self.ssh = None
self.vlun_query_supported = False
self.primera_supported = False

self.debug_rest(debug)

Expand Down Expand Up @@ -230,6 +237,13 @@ def __init__(self, api_url, debug=False, secure=False, timeout=None,
self.HPE3PAR_WS_MIN_BUILD_VERSION_VLUN_QUERY):
self.vlun_query_supported = True

if (api_version['build'] >=
self.HPE3PAR_WS_PRIMERA_MIN_BUILD_VERSION):
self.primera_supported = True

def is_primera_array(self):
return self.primera_supported

def setSSHOptions(self, ip, login, password, port=22,
conn_timeout=None, privatekey=None,
**kwargs):
Expand Down Expand Up @@ -494,8 +508,43 @@ def createVolume(self, name, cpgName, sizeMiB, optional=None):
"""
info = {'name': name, 'cpg': cpgName, 'sizeMiB': sizeMiB}
# For primera array there is no compression and tdvv fields
# removing tdvv and replacing compression with reduce field
if not optional and self.primera_supported:
optional = {}
optional['tpvv'] = True
if optional:
if self.primera_supported:
if 'tdvv' in optional:
optional.pop('tdvv')

if optional.get('tpvv') is True \
and optional.get('compression') is True:
optional['reduce'] = True

if not optional.get('tpvv') \
and not optional.get('compression'):
optional['tpvv'] = True

if 'compression' in optional:
if optional.get('compression') is not None:
if optional.get('compression') is True:
optional['reduce'] = True
elif optional.get('compression') is False:
optional['reduce'] = False
else:
# raising exception for junk compression input
ex_desc = "39 - invalid input: wrong type for value \
- compression"
raise exceptions.HTTPBadRequest(ex_desc)

optional.pop('compression')

if optional.get('tpvv') is True \
and optional.get('reduce') is True:
optional.pop('tpvv')
info = self._mergeDict(info, optional)
logger.debug("Parameters passed for create volume %s" % info)

response, body = self.http.post('/volumes', body=info)
return body
Expand Down Expand Up @@ -913,7 +962,39 @@ def copyVolume(self, src_name, dest_name, dest_cpg, optional=None):
# Virtual volume sets are not supported with the -online option
parameters = {'destVolume': dest_name,
'destCPG': dest_cpg}
# For online copy, there has to be tpvv/tdvv(Non primera array)
# and tpvv/compression(primera array) has to be passed from caller side
# For offline copy, parameters tpvv/tdvv/compression are invalid,
# has to be taken care by caller side
if optional:
if self.primera_supported:
# For primera array there is no compression and tdvv parameters
# removing tdvv and replacing compression with reduce field
if 'tdvv' in optional:
optional.pop('tdvv')

if optional.get('tpvv') is True \
and optional.get('compression') is True:
optional['reduce'] = True

if 'compression' in optional:
if optional.get('compression') is not None:
if optional.get('compression') is True:
optional['reduce'] = True
elif optional.get('compression') is False:
optional['reduce'] = False
else:
# raising exception for junk compression input
ex_desc = "39 - invalid input: wrong type for value \
- compression"
raise exceptions.HTTPBadRequest(ex_desc)

optional.pop('compression')

if optional.get('tpvv') is True \
and optional.get('reduce') is True:
optional.pop('tpvv')

parameters = self._mergeDict(parameters, optional)

if 'online' not in parameters or not parameters['online']:
Expand All @@ -922,7 +1003,7 @@ def copyVolume(self, src_name, dest_name, dest_cpg, optional=None):

info = {'action': 'createPhysicalCopy',
'parameters': parameters}

logger.debug("Parameters passed for copy volume %s" % info)
response, body = self.http.post('/volumes/%s' % src_name, body=info)
return body

Expand Down
9 changes: 7 additions & 2 deletions test/HPE3ParMockServer_flask.py
Expand Up @@ -852,7 +852,7 @@ def create_snapshot(volume_name):
valid_online_param_keys = {'online': None, 'destCPG': None,
'tpvv': None, 'tdvv': None,
'snapCPG': None, 'saveSnapshot': None,
'priority': None}
'priority': None, 'reduce': None}
params = data['parameters']
if 'online' in params and params['online']:
# we are checking online copy
Expand Down Expand Up @@ -950,7 +950,7 @@ def create_volumes():
'tpvv': None, 'usrSpcAllocWarningPct': None,
'usrSpcAllocLimitPct': None, 'isCopy': None,
'copyOfName': None, 'copyRO': None, 'expirationHours': None,
'retentionHours': None}
'retentionHours': None, 'reduce': None}

for key in list(data.keys()):
if key not in list(valid_keys.keys()):
Expand All @@ -976,6 +976,11 @@ def create_volumes():
throw_error(400, TOO_LARGE,
'Volume size is above architectural limit : 16TiB')

if 'tpvv' in list(data.keys()):
if data['tpvv'] not in [True, False, None]:
throw_error(400, INV_INPUT_WRONG_TYPE,
'Invalid input:wrong type for value - tpvv')

if 'id' in list(data.keys()):
for vol in volumes['members']:
if vol['id'] == data['id']:
Expand Down

0 comments on commit aad5522

Please sign in to comment.