Merge "QNAP Drivers - Move from httplib to requests"
This commit is contained in:
commit
9e283258fe
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,6 @@ from collections import OrderedDict
|
|||||||
import eventlet
|
import eventlet
|
||||||
import functools
|
import functools
|
||||||
import re
|
import re
|
||||||
import ssl
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -32,8 +31,8 @@ from oslo_log import log as logging
|
|||||||
from oslo_utils import strutils
|
from oslo_utils import strutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
import requests
|
||||||
import six
|
import six
|
||||||
from six.moves import http_client
|
|
||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
@ -47,12 +46,13 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
qnap_opts = [
|
qnap_opts = [
|
||||||
cfg.URIOpt('qnap_management_url',
|
cfg.URIOpt('qnap_management_url',
|
||||||
help='The URL to management QNAP Storage'),
|
help='The URL to management QNAP Storage. '
|
||||||
|
'Driver does not support IPv6 address in URL.'),
|
||||||
cfg.StrOpt('qnap_poolname',
|
cfg.StrOpt('qnap_poolname',
|
||||||
help='The pool name in the QNAP Storage'),
|
help='The pool name in the QNAP Storage'),
|
||||||
cfg.StrOpt('qnap_storage_protocol',
|
cfg.StrOpt('qnap_storage_protocol',
|
||||||
default='iscsi',
|
default='iscsi',
|
||||||
help='Communication protocol to access QNAP storage'),
|
help='Communication protocol to access QNAP storage')
|
||||||
]
|
]
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@ -74,6 +74,8 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
|||||||
1.2.002:
|
1.2.002:
|
||||||
Add support for QES fw 2.0.0.
|
Add support for QES fw 2.0.0.
|
||||||
|
|
||||||
|
NOTE: Set driver_ssl_cert_verify as True under backend section to
|
||||||
|
enable SSL verification.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ThirdPartySystems wiki page
|
# ThirdPartySystems wiki page
|
||||||
@ -152,7 +154,8 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
|||||||
self.api_executor = QnapAPIExecutor(
|
self.api_executor = QnapAPIExecutor(
|
||||||
username=self.configuration.san_login,
|
username=self.configuration.san_login,
|
||||||
password=self.configuration.san_password,
|
password=self.configuration.san_password,
|
||||||
management_url=self.configuration.qnap_management_url)
|
management_url=self.configuration.qnap_management_url,
|
||||||
|
verify_ssl=self.configuration.driver_ssl_cert_verify)
|
||||||
|
|
||||||
nas_model_name, internal_model_name, fw_version = (
|
nas_model_name, internal_model_name, fw_version = (
|
||||||
self.api_executor.get_basic_info(
|
self.api_executor.get_basic_info(
|
||||||
@ -190,7 +193,8 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
|||||||
return (QnapAPIExecutorTS(
|
return (QnapAPIExecutorTS(
|
||||||
username=self.configuration.san_login,
|
username=self.configuration.san_login,
|
||||||
password=self.configuration.san_password,
|
password=self.configuration.san_password,
|
||||||
management_url=self.configuration.qnap_management_url))
|
management_url=self.configuration.qnap_management_url,
|
||||||
|
verify_ssl=self.configuration.driver_ssl_cert_verify))
|
||||||
elif model_type in tes_model_types:
|
elif model_type in tes_model_types:
|
||||||
if 'TS' in internal_model_name:
|
if 'TS' in internal_model_name:
|
||||||
if (fw_version >= "4.2") and (fw_version <= "4.4"):
|
if (fw_version >= "4.2") and (fw_version <= "4.4"):
|
||||||
@ -202,20 +206,23 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
|||||||
return (QnapAPIExecutorTS(
|
return (QnapAPIExecutorTS(
|
||||||
username=self.configuration.san_login,
|
username=self.configuration.san_login,
|
||||||
password=self.configuration.san_password,
|
password=self.configuration.san_password,
|
||||||
management_url=self.configuration.qnap_management_url))
|
management_url=self.configuration.qnap_management_url,
|
||||||
|
verify_ssl=self.configuration.driver_ssl_cert_verify))
|
||||||
elif "1.1.2" <= fw_version <= "2.0.9999":
|
elif "1.1.2" <= fw_version <= "2.0.9999":
|
||||||
LOG.debug('Create TES API Executor')
|
LOG.debug('Create TES API Executor')
|
||||||
return (QnapAPIExecutorTES(
|
return (QnapAPIExecutorTES(
|
||||||
username=self.configuration.san_login,
|
username=self.configuration.san_login,
|
||||||
password=self.configuration.san_password,
|
password=self.configuration.san_password,
|
||||||
management_url=self.configuration.qnap_management_url))
|
management_url=self.configuration.qnap_management_url,
|
||||||
|
verify_ssl=self.configuration.driver_ssl_cert_verify))
|
||||||
elif model_type in es_model_types:
|
elif model_type in es_model_types:
|
||||||
if "1.1.2" <= fw_version <= "2.0.9999":
|
if "1.1.2" <= fw_version <= "2.0.9999":
|
||||||
LOG.debug('Create ES API Executor')
|
LOG.debug('Create ES API Executor')
|
||||||
return (QnapAPIExecutor(
|
return (QnapAPIExecutor(
|
||||||
username=self.configuration.san_login,
|
username=self.configuration.san_login,
|
||||||
password=self.configuration.san_password,
|
password=self.configuration.san_password,
|
||||||
management_url=self.configuration.qnap_management_url))
|
management_url=self.configuration.qnap_management_url,
|
||||||
|
verify_ssl=self.configuration.driver_ssl_cert_verify))
|
||||||
|
|
||||||
msg = _('Model not support')
|
msg = _('Model not support')
|
||||||
raise exception.VolumeDriverException(message=msg)
|
raise exception.VolumeDriverException(message=msg)
|
||||||
@ -1119,9 +1126,15 @@ class QnapAPIExecutor(object):
|
|||||||
self.password = kwargs['password']
|
self.password = kwargs['password']
|
||||||
self.ip, self.port, self.ssl = (
|
self.ip, self.port, self.ssl = (
|
||||||
self._parse_management_url(kwargs['management_url']))
|
self._parse_management_url(kwargs['management_url']))
|
||||||
|
self.verify_ssl = kwargs['verify_ssl']
|
||||||
self._login()
|
self._login()
|
||||||
|
|
||||||
def _parse_management_url(self, management_url):
|
def _parse_management_url(self, management_url):
|
||||||
|
# NOTE(Ibad): This parser isn't compatible with IPv6 address.
|
||||||
|
# Typical IPv6 address will have : as delimiters and
|
||||||
|
# URL is represented as https://[3ffe:2a00:100:7031::1]:8080
|
||||||
|
# since the regular expression below uses : to identify ip and port
|
||||||
|
# it won't work with IPv6 address.
|
||||||
pattern = re.compile(r"(http|https)\:\/\/(\S+)\:(\d+)")
|
pattern = re.compile(r"(http|https)\:\/\/(\S+)\:(\d+)")
|
||||||
matches = pattern.match(management_url)
|
matches = pattern.match(management_url)
|
||||||
if matches.group(1) == 'http':
|
if matches.group(1) == 'http':
|
||||||
@ -1136,23 +1149,10 @@ class QnapAPIExecutor(object):
|
|||||||
"""Get the basic information of NAS."""
|
"""Get the basic information of NAS."""
|
||||||
management_ip, management_port, management_ssl = (
|
management_ip, management_port, management_ssl = (
|
||||||
self._parse_management_url(management_url))
|
self._parse_management_url(management_url))
|
||||||
connection = None
|
|
||||||
if management_ssl:
|
|
||||||
if hasattr(ssl, '_create_unverified_context'):
|
|
||||||
context = ssl._create_unverified_context()
|
|
||||||
connection = http_client.HTTPSConnection(management_ip,
|
|
||||||
port=management_port,
|
|
||||||
context=context)
|
|
||||||
else:
|
|
||||||
connection = http_client.HTTPSConnection(management_ip,
|
|
||||||
port=management_port)
|
|
||||||
else:
|
|
||||||
connection = (
|
|
||||||
http_client.HTTPConnection(management_ip, management_port))
|
|
||||||
|
|
||||||
connection.request('GET', '/cgi-bin/authLogin.cgi')
|
response = self._get_response(management_ip, management_port,
|
||||||
response = connection.getresponse()
|
management_ssl, '/cgi-bin/authLogin.cgi')
|
||||||
data = response.read()
|
data = response.text
|
||||||
|
|
||||||
root = ET.fromstring(data)
|
root = ET.fromstring(data)
|
||||||
|
|
||||||
@ -1162,6 +1162,29 @@ class QnapAPIExecutor(object):
|
|||||||
|
|
||||||
return nas_model_name, internal_model_name, fw_version
|
return nas_model_name, internal_model_name, fw_version
|
||||||
|
|
||||||
|
def _get_response(self, host_ip, host_port, use_ssl, action, body=None):
|
||||||
|
""""Execute http request and return response."""
|
||||||
|
method = 'GET'
|
||||||
|
headers = None
|
||||||
|
protocol = 'https' if use_ssl else 'http'
|
||||||
|
verify = self.verify_ssl if use_ssl else False
|
||||||
|
# NOTE(ibad): URL formed here isn't IPv6 compatible
|
||||||
|
# we should surround host ip with [] when IPv6 is supported
|
||||||
|
# so the final URL can be like https://[3ffe:2a00:100:7031::1]:8080
|
||||||
|
url = '%s://%s:%s%s' % (protocol, host_ip, host_port, action)
|
||||||
|
|
||||||
|
if body:
|
||||||
|
method = 'POST'
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
'charset': 'utf-8'
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.request(method, url, data=body, headers=headers,
|
||||||
|
verify=verify)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
def _execute_and_get_response_details(self, nas_ip, url, post_parm=None):
|
def _execute_and_get_response_details(self, nas_ip, url, post_parm=None):
|
||||||
"""Will prepare response after executing an http request."""
|
"""Will prepare response after executing an http request."""
|
||||||
LOG.debug('_execute_and_get_response_details url: %s', url)
|
LOG.debug('_execute_and_get_response_details url: %s', url)
|
||||||
@ -1169,53 +1192,23 @@ class QnapAPIExecutor(object):
|
|||||||
|
|
||||||
res_details = {}
|
res_details = {}
|
||||||
|
|
||||||
start_time1 = time.time()
|
|
||||||
|
|
||||||
# Prepare the connection
|
|
||||||
if self.ssl:
|
|
||||||
if hasattr(ssl, '_create_unverified_context'):
|
|
||||||
context = ssl._create_unverified_context()
|
|
||||||
connection = http_client.HTTPSConnection(nas_ip,
|
|
||||||
port=self.port,
|
|
||||||
context=context)
|
|
||||||
else:
|
|
||||||
connection = http_client.HTTPSConnection(
|
|
||||||
nas_ip, port=self.port)
|
|
||||||
else:
|
|
||||||
connection = http_client.HTTPConnection(nas_ip, self.port)
|
|
||||||
|
|
||||||
elapsed_time1 = time.time() - start_time1
|
|
||||||
LOG.debug('connection elapsed_time: %s', elapsed_time1)
|
|
||||||
|
|
||||||
start_time2 = time.time()
|
|
||||||
|
|
||||||
# Make the connection
|
# Make the connection
|
||||||
if post_parm is None:
|
start_time2 = time.time()
|
||||||
connection.request('GET', url)
|
response = self._get_response(
|
||||||
else:
|
nas_ip, self.port, self.ssl, url, post_parm)
|
||||||
headers = {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
"charset": "utf-8"}
|
|
||||||
connection.request('POST', url, post_parm, headers)
|
|
||||||
|
|
||||||
elapsed_time2 = time.time() - start_time2
|
elapsed_time2 = time.time() - start_time2
|
||||||
LOG.debug('request elapsed_time: %s', elapsed_time2)
|
LOG.debug('request elapsed_time: %s', elapsed_time2)
|
||||||
|
|
||||||
# Extract the response as the connection was successful
|
|
||||||
start_time = time.time()
|
|
||||||
response = connection.getresponse()
|
|
||||||
elapsed_time = time.time() - start_time
|
|
||||||
LOG.debug('cgi elapsed_time: %s', elapsed_time)
|
|
||||||
# Read the response
|
# Read the response
|
||||||
data = response.read()
|
data = response.text
|
||||||
LOG.debug('response status: %s', response.status)
|
LOG.debug('response status: %s', response.status_code)
|
||||||
|
|
||||||
# Extract http error msg if any
|
# Extract http error msg if any
|
||||||
error_details = None
|
error_details = None
|
||||||
res_details['data'] = data
|
res_details['data'] = data
|
||||||
res_details['error'] = error_details
|
res_details['error'] = error_details
|
||||||
res_details['http_status'] = response.status
|
res_details['http_status'] = response.status_code
|
||||||
|
|
||||||
connection.close()
|
|
||||||
return res_details
|
return res_details
|
||||||
|
|
||||||
def execute_login(self):
|
def execute_login(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user