summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavanum Srinivas <dims@linux.vnet.ibm.com>2014-09-09 15:01:33 -0400
committerDavanum Srinivas <dims@linux.vnet.ibm.com>2014-09-12 07:24:51 -0400
commit4bd0b4cf7ab45f121aaedfdf55c77aa72bce8b38 (patch)
tree2575b9426104129b6fbe967a25065003af2d1e68
parent5571e9f43597aa7257829f6e4bf6544abfa88880 (diff)
downloadoslo-vmware-4bd0b4cf7ab45f121aaedfdf55c77aa72bce8b38.tar.gz
VMware: Enable vCenter SSL certificate validation
During https/ssl communication the server certificate of a vCenter is not validated during https handshake process. This patch will enable the certificate validation against root certificate of the vCenter to validate the identity of that vCenter. Nova, Cinder etc will need to specify the cacert parameter for this to take effect. Ported from Id: Ic24951630698068321bb62d3098de8344a35c5d0 Closes-Bug: #1276207 Co-Authored-By: Johnson koil raj <johnson.raj@hp.com> Change-Id: I422e6d4df4e392334c0ce47e6f5b017a8c95f61a
-rw-r--r--oslo/vmware/api.py16
-rw-r--r--oslo/vmware/pbm.py8
-rw-r--r--oslo/vmware/service.py33
-rw-r--r--oslo/vmware/vim.py8
-rw-r--r--requirements.txt1
-rw-r--r--tests/test_api.py9
-rw-r--r--tests/test_service.py8
7 files changed, 66 insertions, 17 deletions
diff --git a/oslo/vmware/api.py b/oslo/vmware/api.py
index 5e65786..82ecddf 100644
--- a/oslo/vmware/api.py
+++ b/oslo/vmware/api.py
@@ -143,7 +143,7 @@ class VMwareAPISession(object):
def __init__(self, host, server_username, server_password,
api_retry_count, task_poll_interval, scheme='https',
create_session=True, wsdl_loc=None, pbm_wsdl_loc=None,
- port=443):
+ port=443, cacert=None, insecure=True):
"""Initializes the API session with given parameters.
:param host: ESX/VC server IP address or host name
@@ -159,6 +159,10 @@ class VMwareAPISession(object):
instance creation
:param wsdl_loc: VIM API WSDL file location
:param pbm_wsdl_loc: PBM service WSDL file location
+ :param cacert: Specify a CA bundle file to use in verifying a
+ TLS (https) server certificate.
+ :param insecure: Verify HTTPS connections using system certificates,
+ used only if cacert is not specified
:raises: VimException, VimFaultException, VimAttributeException,
VimSessionOverLoadException
"""
@@ -175,6 +179,8 @@ class VMwareAPISession(object):
self._session_username = None
self._vim = None
self._pbm = None
+ self._cacert = cacert
+ self._insecure = insecure
if create_session:
self._create_session()
@@ -184,7 +190,9 @@ class VMwareAPISession(object):
self._vim = vim.Vim(protocol=self._scheme,
host=self._host,
port=self._port,
- wsdl_url=self._vim_wsdl_loc)
+ wsdl_url=self._vim_wsdl_loc,
+ cacert=self._cacert,
+ insecure=self._insecure)
return self._vim
@property
@@ -193,7 +201,9 @@ class VMwareAPISession(object):
self._pbm = pbm.Pbm(protocol=self._scheme,
host=self._host,
port=self._port,
- wsdl_url=self._pbm_wsdl_loc)
+ wsdl_url=self._pbm_wsdl_loc,
+ cacert=self._cacert,
+ insecure=self._insecure)
if self._session_id:
# To handle the case where pbm property is accessed after
# session creation. If pbm property is accessed before session
diff --git a/oslo/vmware/pbm.py b/oslo/vmware/pbm.py
index 46c9784..005806b 100644
--- a/oslo/vmware/pbm.py
+++ b/oslo/vmware/pbm.py
@@ -41,17 +41,21 @@ class Pbm(service.Service):
"""Service class that provides access to the Storage Policy API."""
def __init__(self, protocol='https', host='localhost', port=443,
- wsdl_url=None):
+ wsdl_url=None, cacert=None, insecure=True):
"""Constructs a PBM service client object.
:param protocol: http or https
:param host: server IP address or host name
:param port: port for connection
:param wsdl_url: PBM WSDL url
+ :param cacert: Specify a CA bundle file to use in verifying a
+ TLS (https) server certificate.
+ :param insecure: Verify HTTPS connections using system certificates,
+ used only if cacert is not specified
"""
base_url = service.Service.build_base_url(protocol, host, port)
soap_url = base_url + '/pbm'
- super(Pbm, self).__init__(wsdl_url, soap_url)
+ super(Pbm, self).__init__(wsdl_url, soap_url, cacert, insecure)
def set_soap_cookie(self, cookie):
"""Set the specified vCenter session cookie in the SOAP header
diff --git a/oslo/vmware/service.py b/oslo/vmware/service.py
index 3b7583f..92a678f 100644
--- a/oslo/vmware/service.py
+++ b/oslo/vmware/service.py
@@ -19,11 +19,12 @@ Common classes that provide access to vSphere services.
import httplib
import logging
-import urllib2
import netaddr
+import requests
import six
import suds
+from suds import transport
from oslo.vmware._i18n import _
from oslo.vmware import exceptions
@@ -68,17 +69,41 @@ class ServiceMessagePlugin(suds.plugin.MessagePlugin):
context.envelope.walk(self.add_attribute_for_value)
+class RequestsTransport(transport.Transport):
+ def __init__(self, cacert=None, insecure=True):
+ transport.Transport.__init__(self)
+ # insecure flag is used only if cacert is not
+ # specified.
+ self.verify = cacert if cacert else not insecure
+ self.session = requests.Session()
+ self.cookiejar = self.session.cookies
+
+ def open(self, request):
+ resp = self.session.get(request.url, verify=self.verify)
+ return six.StringIO(resp.content)
+
+ def send(self, request):
+ resp = self.session.post(request.url,
+ data=request.message,
+ headers=request.headers,
+ verify=self.verify)
+ return transport.Reply(resp.status_code, resp.headers, resp.content)
+
+
class Service(object):
"""Base class containing common functionality for invoking vSphere
services
"""
- def __init__(self, wsdl_url=None, soap_url=None):
+ def __init__(self, wsdl_url=None, soap_url=None,
+ cacert=None, insecure=True):
self.wsdl_url = wsdl_url
self.soap_url = soap_url
LOG.debug("Creating suds client with soap_url='%s' and wsdl_url='%s'",
self.soap_url, self.wsdl_url)
+ transport = RequestsTransport(cacert, insecure)
self.client = suds.client.Client(self.wsdl_url,
+ transport=transport,
location=self.soap_url,
plugins=[ServiceMessagePlugin()],
cache=suds.cache.NoCache())
@@ -206,9 +231,9 @@ class Service(object):
raise exceptions.VimSessionOverLoadException(
_("httplib error in %s.") % attr_name, excep)
- except (urllib2.URLError, urllib2.HTTPError) as excep:
+ except requests.RequestException as excep:
raise exceptions.VimConnectionException(
- _("urllib2 error in %s.") % attr_name, excep)
+ _("requests error in %s.") % attr_name, excep)
except Exception as excep:
# TODO(vbala) should catch specific exceptions and raise
diff --git a/oslo/vmware/vim.py b/oslo/vmware/vim.py
index a9074cf..95a2543 100644
--- a/oslo/vmware/vim.py
+++ b/oslo/vmware/vim.py
@@ -20,13 +20,17 @@ class Vim(service.Service):
"""Service class that provides access to the VIM API."""
def __init__(self, protocol='https', host='localhost', port=None,
- wsdl_url=None):
+ wsdl_url=None, cacert=None, insecure=True):
"""Constructs a VIM service client object.
:param protocol: http or https
:param host: server IP address or host name
:param port: port for connection
:param wsdl_url: VIM WSDL url
+ :param cacert: Specify a CA bundle file to use in verifying a
+ TLS (https) server certificate.
+ :param insecure: Verify HTTPS connections using system certificates,
+ used only if cacert is not specified
:raises: VimException, VimFaultException, VimAttributeException,
VimSessionOverLoadException, VimConnectionException
"""
@@ -34,7 +38,7 @@ class Vim(service.Service):
soap_url = base_url + '/sdk'
if wsdl_url is None:
wsdl_url = soap_url + '/vimService.wsdl'
- super(Vim, self).__init__(wsdl_url, soap_url)
+ super(Vim, self).__init__(wsdl_url, soap_url, cacert, insecure)
def retrieve_service_content(self):
return self.RetrieveServiceContent(service.SERVICE_INSTANCE)
diff --git a/requirements.txt b/requirements.txt
index 57d2aef..55e5eac 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -19,3 +19,4 @@ PyYAML>=3.1.0
suds>=0.4
eventlet>=0.15.1
+requests>=1.2.1,!=2.4.0
diff --git a/tests/test_api.py b/tests/test_api.py
index 6c02051..99730c9 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -108,6 +108,7 @@ class VMwareAPISessionTest(base.TestCase):
self.addCleanup(patcher.stop)
self.VimMock = patcher.start()
self.VimMock.side_effect = lambda *args, **kw: mock.MagicMock()
+ self.cert_mock = mock.Mock()
def _create_api_session(self, _create_session, retry_count=10,
task_poll_interval=1):
@@ -118,7 +119,9 @@ class VMwareAPISessionTest(base.TestCase):
task_poll_interval,
'https',
_create_session,
- port=VMwareAPISessionTest.PORT)
+ port=VMwareAPISessionTest.PORT,
+ cacert=self.cert_mock,
+ insecure=False)
def test_vim(self):
api_session = self._create_api_session(False)
@@ -126,7 +129,9 @@ class VMwareAPISessionTest(base.TestCase):
self.VimMock.assert_called_with(protocol=api_session._scheme,
host=VMwareAPISessionTest.SERVER_IP,
port=VMwareAPISessionTest.PORT,
- wsdl_url=api_session._vim_wsdl_loc)
+ wsdl_url=api_session._vim_wsdl_loc,
+ cacert=self.cert_mock,
+ insecure=False)
@mock.patch.object(pbm, 'Pbm')
def test_pbm(self, pbm_mock):
diff --git a/tests/test_service.py b/tests/test_service.py
index 573772a..bb5d709 100644
--- a/tests/test_service.py
+++ b/tests/test_service.py
@@ -14,9 +14,9 @@
# under the License.
import httplib
-import urllib2
import mock
+import requests
import suds
from oslo.vmware import exceptions
@@ -202,13 +202,13 @@ class ServiceTest(base.TestCase):
svc_obj.powerOn,
managed_object)
- def test_request_handler_with_url_error(self):
+ def test_request_handler_with_connection_error(self):
managed_object = 'VirtualMachine'
def side_effect(mo, **kwargs):
self.assertEqual(managed_object, mo._type)
self.assertEqual(managed_object, mo.value)
- raise urllib2.URLError(None)
+ raise requests.ConnectionError()
svc_obj = service.Service()
attr_name = 'powerOn'
@@ -224,7 +224,7 @@ class ServiceTest(base.TestCase):
def side_effect(mo, **kwargs):
self.assertEqual(managed_object, mo._type)
self.assertEqual(managed_object, mo.value)
- raise urllib2.HTTPError(None, None, None, None, None)
+ raise requests.HTTPError()
svc_obj = service.Service()
attr_name = 'powerOn'