<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>'''
</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>'''
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):
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):
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)
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'
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."""
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
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
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
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:
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:
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
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
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()
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)
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)
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,
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)
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
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
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)
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
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)
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)
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
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)