Add https options and minor code changes
Adds https options x_verify_certificate and x_verify_certificate_path in DotHill and rebranded drivers. Minor cosmetic changes like replacing 'realstor' with 'virtual' and 'wbi' with 'api'. Adding default value for 'x_backend_type' and 'x_api_protocol' options. Minor code optimization for finding array iSCSI addresses. Here 'x' stands for dothill or hpmsa or lenovo. DocImpact Change-Id: I7a5924bbd56053aee6d652842b48e913c54ae7dd Closes-Bug: #1486160 Co-Authored-By: Lakshman <lakshminarayanat@vedams.com> Co-Authored-By: Chris Maio <chris.maio@dothill.com>
This commit is contained in:
parent
fbc59713eb
commit
2c5f154171
|
@ -51,7 +51,7 @@ response_stats_linear = '''<RESPONSE><OBJECT basetype="virtual-disks">
|
|||
<PROPERTY name="size-numeric">3863830528</PROPERTY>
|
||||
<PROPERTY name="freespace-numeric">3863830528</PROPERTY>
|
||||
</OBJECT></RESPONSE>'''
|
||||
response_stats_realstor = '''<RESPONSE><OBJECT basetype="pools">
|
||||
response_stats_virtual = '''<RESPONSE><OBJECT basetype="pools">
|
||||
<PROPERTY name="total-size-numeric">3863830528</PROPERTY>
|
||||
<PROPERTY name="total-avail-numeric">3863830528</PROPERTY>
|
||||
</OBJECT></RESPONSE>'''
|
||||
|
@ -87,7 +87,7 @@ response_ports = '''<RESPONSE>
|
|||
</RESPONSE>'''
|
||||
|
||||
response_ports_linear = response_ports % {'ip': 'primary-ip-address'}
|
||||
response_ports_realstor = response_ports % {'ip': 'ip-address'}
|
||||
response_ports_virtual = response_ports % {'ip': 'ip-address'}
|
||||
|
||||
|
||||
invalid_xml = '''<RESPONSE></RESPONSE>'''
|
||||
|
@ -146,8 +146,9 @@ class TestDotHillClient(test.TestCase):
|
|||
self.passwd = '!manage'
|
||||
self.ip = '10.0.0.1'
|
||||
self.protocol = 'http'
|
||||
self.ssl_verify = False
|
||||
self.client = dothill.DotHillClient(self.ip, self.login, self.passwd,
|
||||
self.protocol)
|
||||
self.protocol, self.ssl_verify)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_login(self, mock_requests_get):
|
||||
|
@ -219,13 +220,13 @@ class TestDotHillClient(test.TestCase):
|
|||
stats = {'free_capacity_gb': 1979,
|
||||
'total_capacity_gb': 1979}
|
||||
linear = etree.XML(response_stats_linear)
|
||||
realstor = etree.XML(response_stats_realstor)
|
||||
mock_request.side_effect = [linear, realstor]
|
||||
virtual = etree.XML(response_stats_virtual)
|
||||
mock_request.side_effect = [linear, virtual]
|
||||
|
||||
self.assertEqual(stats, self.client.backend_stats('OpenStack',
|
||||
'linear'))
|
||||
self.assertEqual(stats, self.client.backend_stats('OpenStack',
|
||||
'realstor'))
|
||||
self.assertEqual(stats, self.client.backend_stats('A',
|
||||
'virtual'))
|
||||
|
||||
@mock.patch.object(dothill.DotHillClient, '_request')
|
||||
def test_get_lun(self, mock_request):
|
||||
|
@ -266,10 +267,10 @@ class TestDotHillClient(test.TestCase):
|
|||
def test_get_iscsi_portals(self, mock_request):
|
||||
portals = {'10.0.0.12': 'Up', '10.0.0.11': 'Up'}
|
||||
mock_request.side_effect = [etree.XML(response_ports_linear),
|
||||
etree.XML(response_ports_realstor)]
|
||||
ret = self.client.get_active_iscsi_target_portals('linear')
|
||||
etree.XML(response_ports_virtual)]
|
||||
ret = self.client.get_active_iscsi_target_portals()
|
||||
self.assertEqual(portals, ret)
|
||||
ret = self.client.get_active_iscsi_target_portals('realstor')
|
||||
ret = self.client.get_active_iscsi_target_portals()
|
||||
self.assertEqual(portals, ret)
|
||||
|
||||
|
||||
|
@ -279,7 +280,7 @@ class FakeConfiguration1(object):
|
|||
san_ip = '10.0.0.1'
|
||||
san_login = 'manage'
|
||||
san_password = '!manage'
|
||||
dothill_wbi_protocol = 'http'
|
||||
dothill_api_protocol = 'http'
|
||||
|
||||
def safe_get(self, key):
|
||||
return 'fakevalue'
|
||||
|
|
|
@ -30,11 +30,12 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class DotHillClient(object):
|
||||
def __init__(self, host, login, password, protocol):
|
||||
def __init__(self, host, login, password, protocol, ssl_verify):
|
||||
self._login = login
|
||||
self._password = password
|
||||
self._base_url = "%s://%s/api" % (protocol, host)
|
||||
self._session_key = None
|
||||
self.ssl_verify = ssl_verify
|
||||
|
||||
def _get_auth_token(self, xml):
|
||||
"""Parse an XML authentication reply to extract the session key."""
|
||||
|
@ -53,7 +54,7 @@ class DotHillClient(object):
|
|||
|
||||
url = self._base_url + "/login/" + digest
|
||||
try:
|
||||
xml = requests.get(url)
|
||||
xml = requests.get(url, verify=self.ssl_verify)
|
||||
except requests.exceptions.RequestException:
|
||||
raise exception.DotHillConnectionError
|
||||
|
||||
|
@ -96,7 +97,7 @@ class DotHillClient(object):
|
|||
url = self._build_request_url(path, *args, **kargs)
|
||||
headers = {'dataType': 'api', 'sessionKey': self._session_key}
|
||||
try:
|
||||
xml = requests.get(url, headers=headers)
|
||||
xml = requests.get(url, headers=headers, verify=self.ssl_verify)
|
||||
tree = etree.XML(xml.text.encode('utf8'))
|
||||
except Exception:
|
||||
raise exception.DotHillConnectionError
|
||||
|
@ -109,7 +110,7 @@ class DotHillClient(object):
|
|||
def logout(self):
|
||||
url = self._base_url + '/exit'
|
||||
try:
|
||||
requests.get(url)
|
||||
requests.get(url, verify=self.ssl_verify)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
@ -275,10 +276,10 @@ class DotHillClient(object):
|
|||
return host_status
|
||||
|
||||
def _safe_hostname(self, hostname):
|
||||
"""DotHill hostname restrictions.
|
||||
"""Modify an initiator name to match firmware requirements.
|
||||
|
||||
A host name cannot include " , \ in linear and " , < > \ in realstor
|
||||
and can have a max of 15 bytes in linear and 32 bytes in realstor.
|
||||
Initiator name cannot include certain characters and cannot exceed
|
||||
15 bytes in 'T' firmware (32 bytes in 'G' firmware).
|
||||
"""
|
||||
for ch in [',', '"', '\\', '<', '>']:
|
||||
if ch in hostname:
|
||||
|
@ -288,16 +289,14 @@ class DotHillClient(object):
|
|||
index = 15
|
||||
return hostname[:index]
|
||||
|
||||
def get_active_iscsi_target_portals(self, backend_type):
|
||||
def get_active_iscsi_target_portals(self):
|
||||
# This function returns {'ip': status,}
|
||||
portals = {}
|
||||
prop = ""
|
||||
prop = 'ip-address'
|
||||
tree = self._request("/show/ports")
|
||||
if backend_type == "linear":
|
||||
prop = "primary-ip-address"
|
||||
else:
|
||||
prop = "ip-address"
|
||||
|
||||
for el in tree.xpath("//PROPERTY[@name='primary-ip-address']"):
|
||||
prop = 'primary-ip-address'
|
||||
break
|
||||
iscsi_ips = [ip.text for ip in tree.xpath(
|
||||
"//PROPERTY[@name='%s']" % prop)]
|
||||
if not iscsi_ips:
|
||||
|
|
|
@ -32,20 +32,28 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
common_opt = [
|
||||
cfg.StrOpt('dothill_backend_name',
|
||||
default='OpenStack',
|
||||
help="VDisk or Pool name to use for volume creation."),
|
||||
default='A',
|
||||
help="Pool or Vdisk name to use for volume creation."),
|
||||
cfg.StrOpt('dothill_backend_type',
|
||||
choices=['linear', 'realstor'],
|
||||
help="linear (for VDisk) or realstor (for Pool)."),
|
||||
cfg.StrOpt('dothill_wbi_protocol',
|
||||
choices=['linear', 'virtual'],
|
||||
default='virtual',
|
||||
help="linear (for Vdisk) or virtual (for Pool)."),
|
||||
cfg.StrOpt('dothill_api_protocol',
|
||||
choices=['http', 'https'],
|
||||
help="DotHill web interface protocol."),
|
||||
default='https',
|
||||
help="DotHill API interface protocol."),
|
||||
cfg.BoolOpt('dothill_verify_certificate',
|
||||
default=False,
|
||||
help="Whether to verify DotHill array SSL certificate."),
|
||||
cfg.StrOpt('dothill_verify_certificate_path',
|
||||
default=None,
|
||||
help="DotHill array SSL certificate path."),
|
||||
]
|
||||
|
||||
iscsi_opt = [
|
||||
cfg.ListOpt('dothill_iscsi_ips',
|
||||
default=[],
|
||||
help="List of comma separated target iSCSI IP addresses."),
|
||||
help="List of comma-separated target iSCSI IP addresses."),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -63,10 +71,16 @@ class DotHillCommon(object):
|
|||
self.vendor_name = "DotHill"
|
||||
self.backend_name = self.config.dothill_backend_name
|
||||
self.backend_type = self.config.dothill_backend_type
|
||||
self.api_protocol = self.config.dothill_api_protocol
|
||||
ssl_verify = False
|
||||
if (self.api_protocol == 'https' and
|
||||
self.config.dothill_verify_certificate):
|
||||
ssl_verify = self.config.dothill_verify_certificate_path or True
|
||||
self.client = dothill.DotHillClient(self.config.san_ip,
|
||||
self.config.san_login,
|
||||
self.config.san_password,
|
||||
self.config.dothill_wbi_protocol)
|
||||
self.api_protocol,
|
||||
ssl_verify)
|
||||
|
||||
def get_version(self):
|
||||
return self.VERSION
|
||||
|
@ -75,7 +89,7 @@ class DotHillCommon(object):
|
|||
self.client_login()
|
||||
self._validate_backend()
|
||||
if (self.backend_type == "linear" or
|
||||
(self.backend_type == "realstor" and
|
||||
(self.backend_type == "virtual" and
|
||||
self.backend_name not in ['A', 'B'])):
|
||||
self._get_owner_info(self.backend_name)
|
||||
self._get_serial_number()
|
||||
|
@ -194,7 +208,7 @@ class DotHillCommon(object):
|
|||
raise exception.VolumeAttached(volume_id=volume['id'])
|
||||
|
||||
def create_cloned_volume(self, volume, src_vref):
|
||||
if self.backend_type == "realstor" and self.backend_name in ["A", "B"]:
|
||||
if self.backend_type == "virtual" and self.backend_name in ["A", "B"]:
|
||||
msg = _("Create volume from volume(clone) does not have support "
|
||||
"for virtual pool A and B.")
|
||||
LOG.error(msg)
|
||||
|
@ -223,7 +237,7 @@ class DotHillCommon(object):
|
|||
self.client_logout()
|
||||
|
||||
def create_volume_from_snapshot(self, volume, snapshot):
|
||||
if self.backend_type == "realstor" and self.backend_name in ["A", "B"]:
|
||||
if self.backend_type == "virtual" and self.backend_name in ["A", "B"]:
|
||||
msg = _('Create volume from snapshot does not have support '
|
||||
'for virtual pool A and B.')
|
||||
LOG.error(msg)
|
||||
|
@ -290,7 +304,7 @@ class DotHillCommon(object):
|
|||
self.backend_type)
|
||||
pool.update(backend_stats)
|
||||
if (self.backend_type == "linear" or
|
||||
(self.backend_type == "realstor" and
|
||||
(self.backend_type == "virtual" and
|
||||
self.backend_name not in ['A', 'B'])):
|
||||
pool['location_info'] = ('%s:%s:%s:%s' %
|
||||
(src_type,
|
||||
|
@ -362,8 +376,7 @@ class DotHillCommon(object):
|
|||
|
||||
def get_active_iscsi_target_portals(self):
|
||||
try:
|
||||
return self.client.get_active_iscsi_target_portals(
|
||||
self.backend_type)
|
||||
return self.client.get_active_iscsi_target_portals()
|
||||
except exception.DotHillRequestError as ex:
|
||||
LOG.exception(_LE("Error getting active ISCSI target portals."))
|
||||
raise exception.Invalid(ex)
|
||||
|
|
|
@ -33,7 +33,7 @@ class DotHillFCDriver(cinder.volume.driver.FibreChannelDriver):
|
|||
cinder/volume/drivers/san/hp"
|
||||
1.0 - Version developed for DotHill arrays with the following
|
||||
modifications:
|
||||
- added support for v3 API(realstor feature)
|
||||
- added support for v3 API(virtual pool feature)
|
||||
- added support for retype volume
|
||||
- added support for manage/unmanage volume
|
||||
- added initiator target mapping in FC zoning
|
||||
|
|
|
@ -39,7 +39,7 @@ class DotHillISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
|||
modifications:
|
||||
- added iSCSI support
|
||||
- added CHAP support in iSCSI
|
||||
- added support for v3 API(realstor feature)
|
||||
- added support for v3 API(virtual pool feature)
|
||||
- added support for retype volume
|
||||
- added support for manage/unmanage volume
|
||||
- added https support
|
||||
|
|
|
@ -19,5 +19,6 @@ from cinder.volume.drivers.dothill import dothill_client
|
|||
|
||||
class LenovoClient(dothill_client.DotHillClient):
|
||||
|
||||
def __init__(self, host, login, password, protocol):
|
||||
super(LenovoClient, self).__init__(host, login, password, protocol)
|
||||
def __init__(self, host, login, password, protocol, ssl_verify):
|
||||
super(LenovoClient, self).__init__(host, login, password, protocol,
|
||||
ssl_verify)
|
||||
|
|
|
@ -21,20 +21,28 @@ from cinder.volume.drivers.lenovo import lenovo_client
|
|||
|
||||
common_opt = [
|
||||
cfg.StrOpt('lenovo_backend_name',
|
||||
default='OpenStack',
|
||||
help="VDisk or Pool name to use for volume creation."),
|
||||
default='A',
|
||||
help="Pool or Vdisk name to use for volume creation."),
|
||||
cfg.StrOpt('lenovo_backend_type',
|
||||
choices=['linear', 'realstor'],
|
||||
help="linear (for VDisk) or realstor (for Pool)."),
|
||||
cfg.StrOpt('lenovo_wbi_protocol',
|
||||
choices=['linear', 'virtual'],
|
||||
default='virtual',
|
||||
help="linear (for VDisk) or virtual (for Pool)."),
|
||||
cfg.StrOpt('lenovo_api_protocol',
|
||||
choices=['http', 'https'],
|
||||
help="Lenovo web interface protocol."),
|
||||
default='https',
|
||||
help="Lenovo api interface protocol."),
|
||||
cfg.BoolOpt('lenovo_verify_certificate',
|
||||
default=False,
|
||||
help="Whether to verify Lenovo array SSL certificate."),
|
||||
cfg.StrOpt('lenovo_verify_certificate_path',
|
||||
default=None,
|
||||
help="Lenovo array SSL certificate path.")
|
||||
]
|
||||
|
||||
iscsi_opt = [
|
||||
cfg.ListOpt('lenovo_iscsi_ips',
|
||||
default=[],
|
||||
help="List of comma separated target iSCSI IP addresses."),
|
||||
help="List of comma-separated target iSCSI IP addresses."),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -50,8 +58,13 @@ class LenovoCommon(dothill_common.DotHillCommon):
|
|||
self.vendor_name = "Lenovo"
|
||||
self.backend_name = self.config.lenovo_backend_name
|
||||
self.backend_type = self.config.lenovo_backend_type
|
||||
self.wbi_protocol = self.config.lenovo_wbi_protocol
|
||||
self.api_protocol = self.config.lenovo_api_protocol
|
||||
ssl_verify = False
|
||||
if (self.api_protocol == 'https' and
|
||||
self.config.lenovo_verify_certificate):
|
||||
ssl_verify = self.config.lenovo_verify_certificate_path or True
|
||||
self.client = lenovo_client.LenovoClient(self.config.san_ip,
|
||||
self.config.san_login,
|
||||
self.config.san_password,
|
||||
self.wbi_protocol)
|
||||
self.api_protocol,
|
||||
ssl_verify)
|
||||
|
|
|
@ -19,6 +19,6 @@ from cinder.volume.drivers.dothill import dothill_client
|
|||
|
||||
class HPMSAClient(dothill_client.DotHillClient):
|
||||
|
||||
def __init__(self, host, login, password, protocol):
|
||||
def __init__(self, host, login, password, protocol, ssl_verify):
|
||||
super(HPMSAClient, self).__init__(host, login, password,
|
||||
protocol)
|
||||
protocol, ssl_verify)
|
||||
|
|
|
@ -21,20 +21,29 @@ from cinder.volume.drivers.san.hp import hpmsa_client
|
|||
|
||||
common_opt = [
|
||||
cfg.StrOpt('hpmsa_backend_name',
|
||||
default='OpenStack',
|
||||
help="VDisk or Pool name to use for volume creation."),
|
||||
default='A',
|
||||
help="Pool or Vdisk name to use for volume creation."),
|
||||
cfg.StrOpt('hpmsa_backend_type',
|
||||
choices=['linear', 'realstor'],
|
||||
help="linear (for VDisk) or realstor (for Pool)."),
|
||||
cfg.StrOpt('hpmsa_wbi_protocol',
|
||||
choices=['linear', 'virtual'],
|
||||
default='virtual',
|
||||
help="linear (for Vdisk) or virtual (for Pool)."),
|
||||
cfg.StrOpt('hpmsa_api_protocol',
|
||||
choices=['http', 'https'],
|
||||
help="HPMSA web interface protocol."),
|
||||
default='https',
|
||||
help="HPMSA API interface protocol."),
|
||||
cfg.BoolOpt('hpmsa_verify_certificate',
|
||||
default=False,
|
||||
help="Whether to verify HPMSA array SSL certificate."),
|
||||
cfg.StrOpt('hpmsa_verify_certificate_path',
|
||||
default=None,
|
||||
help="HPMSA array SSL certificate path."),
|
||||
|
||||
]
|
||||
|
||||
iscsi_opt = [
|
||||
cfg.ListOpt('hpmsa_iscsi_ips',
|
||||
default=[],
|
||||
help="List of comma separated target iSCSI IP addresses."),
|
||||
help="List of comma-separated target iSCSI IP addresses."),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -50,7 +59,14 @@ class HPMSACommon(dothill_common.DotHillCommon):
|
|||
self.vendor_name = "HPMSA"
|
||||
self.backend_name = self.config.hpmsa_backend_name
|
||||
self.backend_type = self.config.hpmsa_backend_type
|
||||
self.api_protocol = self.config.hpmsa_api_protocol
|
||||
ssl_verify = False
|
||||
if (self.api_protocol == 'https' and
|
||||
self.config.hpmsa_verify_certificate):
|
||||
ssl_verify = self.config.hpmsa_verify_certificate_path or True
|
||||
|
||||
self.client = hpmsa_client.HPMSAClient(self.config.san_ip,
|
||||
self.config.san_login,
|
||||
self.config.san_password,
|
||||
self.config.hpmsa_wbi_protocol)
|
||||
self.api_protocol,
|
||||
ssl_verify)
|
||||
|
|
Loading…
Reference in New Issue