Browse Source

[NetApp] Fix HTTPS connection for python 3.7

With python3.7, the eventlet is breaking the ssl.py, so the https
is not working. This patch fixes it by changing the request library
(urllib by requests), the new library can be built over the
pyopenssl.py instead of ssl.py.

Closes-Bug: #1878993
Change-Id: I9c0b1f332ead25634f3dc3aebfdc8b51dfbc4178
(cherry picked from commit 29622725e4)
changes/56/737756/1
Felipe Rodrigues 1 year ago
committed by Douglas Viroel
parent
commit
2dbdace661
  1. 51
      manila/share/drivers/netapp/dataontap/client/api.py
  2. 4
      manila/tests/share/drivers/netapp/dataontap/client/fakes.py
  3. 47
      manila/tests/share/drivers/netapp/dataontap/client/test_api.py
  4. 6
      releasenotes/notes/bug-1878993-netapp-fix-https-3eddf9eb5b762f3a.yaml

51
manila/share/drivers/netapp/dataontap/client/api.py

@ -23,8 +23,9 @@ import re
from lxml import etree
from oslo_log import log
import requests
from requests import auth
import six
from six.moves import urllib
from manila import exception
from manila.i18n import _
@ -61,6 +62,7 @@ class NaServer(object):
TRANSPORT_TYPE_HTTP = 'http'
TRANSPORT_TYPE_HTTPS = 'https'
SSL_CERT_DEFAULT = "/etc/ssl/certs/"
SERVER_TYPE_FILER = 'filer'
SERVER_TYPE_DFM = 'dfm'
URL_FILER = 'servlets/netapp.servlets.admin.XMLrequest_filer'
@ -232,8 +234,8 @@ class NaServer(object):
"""Invoke the API on the server."""
if na_element and not isinstance(na_element, NaElement):
ValueError('NaElement must be supplied to invoke API')
request, request_element = self._create_request(na_element,
enable_tunneling)
request_element = self._create_request(na_element, enable_tunneling)
request_d = request_element.to_string()
api_name = na_element.get_name()
api_name_matches_regex = (re.match(self._api_trace_pattern, api_name)
@ -242,23 +244,26 @@ class NaServer(object):
if self._trace and api_name_matches_regex:
LOG.debug("Request: %s", request_element.to_string(pretty=True))
if (not hasattr(self, '_opener') or not self._opener
if (not hasattr(self, '_session') or not self._session
or self._refresh_conn):
self._build_opener()
self._build_session()
try:
if hasattr(self, '_timeout'):
response = self._opener.open(request, timeout=self._timeout)
response = self._session.post(
self._get_url(), data=request_d, timeout=self._timeout)
else:
response = self._opener.open(request)
except urllib.error.HTTPError as e:
raise NaApiError(e.code, e.msg)
except urllib.error.URLError as e:
response = self._session.post(
self._get_url(), data=request_d)
except requests.HTTPError as e:
raise NaApiError(e.errno, e.strerror)
except requests.URLRequired as e:
raise exception.StorageCommunicationException(six.text_type(e))
except Exception as e:
raise NaApiError(message=e)
response_xml = response.read()
response_element = self._get_result(response_xml)
response_xml = response.text
response_element = self._get_result(
bytes(bytearray(response_xml, encoding='utf-8')))
if self._trace and api_name_matches_regex:
LOG.debug("Response: %s", response_element.to_string(pretty=True))
@ -296,11 +301,7 @@ class NaServer(object):
if enable_tunneling:
self._enable_tunnel_request(netapp_elem)
netapp_elem.add_child_elem(na_element)
request_d = netapp_elem.to_string()
request = urllib.request.Request(
self._get_url(), data=request_d,
headers={'Content-Type': 'text/xml', 'charset': 'utf-8'})
return request, netapp_elem
return netapp_elem
def _enable_tunnel_request(self, netapp_elem):
"""Enables vserver or vfiler tunneling."""
@ -341,20 +342,20 @@ class NaServer(object):
host = '[%s]' % host
return '%s://%s:%s/%s' % (self._protocol, host, self._port, self._url)
def _build_opener(self):
def _build_session(self):
if self._auth_style == NaServer.STYLE_LOGIN_PASSWORD:
auth_handler = self._create_basic_auth_handler()
else:
auth_handler = self._create_certificate_auth_handler()
opener = urllib.request.build_opener(auth_handler)
self._opener = opener
self._session = requests.Session()
self._session.auth = auth_handler
self._session.verify = NaServer.SSL_CERT_DEFAULT
self._session.headers = {
'Content-Type': 'text/xml', 'charset': 'utf-8'}
def _create_basic_auth_handler(self):
password_man = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_man.add_password(None, self._get_url(), self._username,
self._password)
auth_handler = urllib.request.HTTPBasicAuthHandler(password_man)
return auth_handler
return auth.HTTPBasicAuth(self._username, self._password)
def _create_certificate_auth_handler(self):
raise NotImplementedError()

4
manila/tests/share/drivers/netapp/dataontap/client/fakes.py

@ -15,7 +15,7 @@
from unittest import mock
from lxml import etree
from six.moves import urllib
import requests
from manila.share.drivers.netapp.dataontap.client import api
@ -2638,7 +2638,7 @@ FAKE_RESULT_API_ERRNO_VALID.add_attr('errno', '14956')
FAKE_RESULT_SUCCESS = api.NaElement('result')
FAKE_RESULT_SUCCESS.add_attr('status', 'passed')
FAKE_HTTP_OPENER = urllib.request.build_opener()
FAKE_HTTP_SESSION = requests.Session()
FAKE_MANAGE_VOLUME = {
'aggregate': SHARE_AGGREGATE_NAME,

47
manila/tests/share/drivers/netapp/dataontap/client/test_api.py

@ -22,7 +22,7 @@ Tests for NetApp API layer
from unittest import mock
import ddt
from six.moves import urllib
import requests
from manila import exception
from manila.share.drivers.netapp.dataontap.client import api
@ -190,14 +190,12 @@ class NetAppApiServerTests(test.TestCase):
"""Tests handling of HTTPError"""
na_element = fake.FAKE_NA_ELEMENT
self.mock_object(self.root, '_create_request', mock.Mock(
return_value=('abc', fake.FAKE_NA_ELEMENT)))
return_value=fake.FAKE_NA_ELEMENT))
self.mock_object(api, 'LOG')
self.root._opener = fake.FAKE_HTTP_OPENER
self.mock_object(self.root, '_build_opener')
self.mock_object(self.root._opener, 'open', mock.Mock(
side_effect=urllib.error.HTTPError(url='', hdrs='',
fp=None, code='401',
msg='httperror')))
self.root._session = fake.FAKE_HTTP_SESSION
self.mock_object(self.root, '_build_session')
self.mock_object(self.root._session, 'post', mock.Mock(
side_effect=requests.HTTPError()))
self.assertRaises(api.NaApiError, self.root.invoke_elem,
na_element)
@ -206,12 +204,12 @@ class NetAppApiServerTests(test.TestCase):
"""Tests handling of URLError"""
na_element = fake.FAKE_NA_ELEMENT
self.mock_object(self.root, '_create_request', mock.Mock(
return_value=('abc', fake.FAKE_NA_ELEMENT)))
return_value=fake.FAKE_NA_ELEMENT))
self.mock_object(api, 'LOG')
self.root._opener = fake.FAKE_HTTP_OPENER
self.mock_object(self.root, '_build_opener')
self.mock_object(self.root._opener, 'open', mock.Mock(
side_effect=urllib.error.URLError(reason='urlerror')))
self.root._session = fake.FAKE_HTTP_SESSION
self.mock_object(self.root, '_build_session')
self.mock_object(self.root._session, 'post', mock.Mock(
side_effect=requests.URLRequired()))
self.assertRaises(exception.StorageCommunicationException,
self.root.invoke_elem,
@ -221,11 +219,11 @@ class NetAppApiServerTests(test.TestCase):
"""Tests handling of Unknown Exception"""
na_element = fake.FAKE_NA_ELEMENT
self.mock_object(self.root, '_create_request', mock.Mock(
return_value=('abc', fake.FAKE_NA_ELEMENT)))
return_value=fake.FAKE_NA_ELEMENT))
self.mock_object(api, 'LOG')
self.root._opener = fake.FAKE_HTTP_OPENER
self.mock_object(self.root, '_build_opener')
self.mock_object(self.root._opener, 'open', mock.Mock(
self.root._session = fake.FAKE_HTTP_SESSION
self.mock_object(self.root, '_build_session')
self.mock_object(self.root._session, 'post', mock.Mock(
side_effect=Exception))
exception = self.assertRaises(api.NaApiError, self.root.invoke_elem,
@ -247,15 +245,18 @@ class NetAppApiServerTests(test.TestCase):
self.root._trace = trace_enabled
self.root._api_trace_pattern = trace_pattern
self.mock_object(self.root, '_create_request', mock.Mock(
return_value=('abc', fake.FAKE_NA_ELEMENT)))
return_value=fake.FAKE_NA_ELEMENT))
self.mock_object(api, 'LOG')
self.root._opener = fake.FAKE_HTTP_OPENER
self.mock_object(self.root, '_build_opener')
self.root._session = fake.FAKE_HTTP_SESSION
self.mock_object(self.root, '_build_session')
self.mock_object(self.root, '_get_result', mock.Mock(
return_value=fake.FAKE_NA_ELEMENT))
opener_mock = self.mock_object(
self.root._opener, 'open', mock.Mock())
opener_mock.read.side_effect = ['resp1', 'resp2']
response = mock.Mock()
response.text = 'res1'
self.mock_object(
self.root._session, 'post', mock.Mock(
return_value=response))
self.root.invoke_elem(na_element)

6
releasenotes/notes/bug-1878993-netapp-fix-https-3eddf9eb5b762f3a.yaml

@ -0,0 +1,6 @@
---
fixes:
- |
Fixed `bug #1878993 <https://bugs.launchpad.net/manila/+bug/1878993>`_
that caused a failure on HTTPS connections within NetApp backend using
python 3.7.
Loading…
Cancel
Save