Skip to content

Commit

Permalink
fix pvmomi the proxy support
Browse files Browse the repository at this point in the history
- ensure the proxy configuration is passed to `__GetElementTree()`
- ruse @blacksponge fix for the  `SSLTunnelConnection` class
- remove `test_ssl_tunnel_http_failure` because the error will happen
  later
- add `test_ssl_tunnelwith_cert_file` test to validate that `cert_file`
  and `key_file` are passed as expected.

closes: #620
closes: #567
closes: #198
  • Loading branch information
goneri committed Jun 19, 2019
1 parent 3ffcb23 commit aef6121
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 52 deletions.
27 changes: 19 additions & 8 deletions pyVim/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ def __exit__(self, *exc_info):
Disconnect(self.si)
self.si = None

def __GetElementTree(protocol, server, port, path, sslContext):
def __GetElementTree(protocol, server, port, path, sslContext, httpProxyHost=None, httpProxyPort=None):
"""
Private method that returns a root from ElementTree for a remote XML document.
Expand All @@ -594,7 +594,11 @@ def __GetElementTree(protocol, server, port, path, sslContext):
@type sslContext: SSL.Context
"""

if protocol == "https":
if httpProxyHost:
kwargs = {"context": sslContext} if sslContext else {}
conn = http_client.HTTPSConnection(httpProxyHost, port=httpProxyPort, **kwargs)
conn.set_tunnel(server, port)
elif protocol == "https":
kwargs = {"context": sslContext} if sslContext else {}
conn = http_client.HTTPSConnection(server, port=port, **kwargs)
elif protocol == "http":
Expand All @@ -615,7 +619,7 @@ def __GetElementTree(protocol, server, port, path, sslContext):
## supported by the specified server. The result will be vimServiceVersions.xml
## if it exists, otherwise vimService.wsdl if it exists, otherwise None.

def __GetServiceVersionDescription(protocol, server, port, path, sslContext):
def __GetServiceVersionDescription(protocol, server, port, path, sslContext, httpProxyHost=None, httpProxyPort=None):
"""
Private method that returns a root from an ElementTree describing the API versions
supported by the specified server. The result will be vimServiceVersions.xml
Expand All @@ -635,12 +639,14 @@ def __GetServiceVersionDescription(protocol, server, port, path, sslContext):
"""

tree = __GetElementTree(protocol, server, port,
path + "/vimServiceVersions.xml", sslContext)
path + "/vimServiceVersions.xml", sslContext,
httpProxyHost, httpProxyPort)
if tree is not None:
return tree

tree = __GetElementTree(protocol, server, port,
path + "/vimService.wsdl", sslContext)
path + "/vimService.wsdl", sslContext,
httpProxyHost, httpProxyPort)
return tree


Expand Down Expand Up @@ -689,7 +695,7 @@ def __VersionIsSupported(desiredVersion, serviceVersionDescription):
## Private method that returns the most preferred API version supported by the
## specified server,

def __FindSupportedVersion(protocol, server, port, path, preferredApiVersions, sslContext):
def __FindSupportedVersion(protocol, server, port, path, preferredApiVersions, sslContext, httpProxyHost=None, httpProxyPort=None):
"""
Private method that returns the most preferred API version supported by the
specified server,
Expand All @@ -715,7 +721,9 @@ def __FindSupportedVersion(protocol, server, port, path, preferredApiVersions, s
server,
port,
path,
sslContext)
sslContext,
httpProxyHost,
httpProxyPort)
if serviceVersionDescription is None:
return None

Expand Down Expand Up @@ -759,7 +767,10 @@ def SmartStubAdapter(host='localhost', port=443, path='/sdk',
port,
path,
preferredApiVersions,
sslContext)
sslContext,
httpProxyHost,
httpProxyPort
)
if supportedVersion is None:
raise Exception("%s:%s is not a VIM server" % (host, port))

Expand Down
27 changes: 6 additions & 21 deletions pyVmomi/SoapAdapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1072,27 +1072,12 @@ def __init__(self, proxyPath):
# specified by proxyPath. If successful, a new HTTPSConnection is returned.
#
# @param path The destination URL path.
# @param key_file The SSL key file to use when wrapping the socket.
# @param cert_file The SSL certificate file to use when wrapping the socket.
# @param kwargs In case caller passed in extra parameters not handled by
# SSLTunnelConnection
def __call__(self, path, key_file=None, cert_file=None, **kwargs):
# Only pass in the named arguments that HTTPConnection constructor
# understands
tmpKwargs = {}
for key in http_client.HTTPConnection.__init__.__code__.co_varnames:
if key in kwargs and key != 'self':
tmpKwargs[key] = kwargs[key]
tunnel = http_client.HTTPConnection(path, **tmpKwargs)
tunnel.request('CONNECT', self.proxyPath)
resp = tunnel.getresponse()
if resp.status != 200:
raise http_client.HTTPException("{0} {1}".format(resp.status, resp.reason))
retval = http_client.HTTPSConnection(path)
retval.sock = _SocketWrapper(tunnel.sock,
keyfile=key_file, certfile=cert_file)
return retval

# @param args Arguments are ignored
# @param kwargs Arguments for HTTPSConnection
def __call__(self, path, *args, **kwargs):
conn = http_client.HTTPSConnection(path, **kwargs)
conn.set_tunnel(self.proxyPath)
return conn

class GzipReader:
GZIP = 1
Expand Down
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
tox
testtools>=0.9.34
vcrpy<2
mock
15 changes: 0 additions & 15 deletions tests/fixtures/ssl_tunnel_http_failure.yaml

This file was deleted.

23 changes: 15 additions & 8 deletions tests/test_connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,16 @@

import tests
import unittest
import sys

from pyVim import connect
from pyVmomi import vim

if sys.version_info >= (3, 3):
from unittest.mock import patch, MagicMock
else:
from mock import patch, MagicMock


class ConnectionTests(tests.VCRTestBase):

Expand Down Expand Up @@ -89,14 +95,15 @@ def test_disconnect_on_no_connection(self):
def test_ssl_tunnel(self):
connect.SoapStubAdapter('sdkTunnel', 8089, httpProxyHost='vcsa').GetConnection()

@tests.VCRTestBase.my_vcr.use_cassette('ssl_tunnel_http_failure.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='none')
def test_ssl_tunnel_http_failure(self):
from six.moves import http_client
def should_fail():
connect.SoapStubAdapter('vcsa', 80, httpProxyHost='vcsa').GetConnection()
self.assertRaises(http_client.HTTPException, should_fail)
@patch('six.moves.http_client.HTTPSConnection')
def test_ssl_tunnelwith_cert_file(self, hs):
conn = connect.SoapStubAdapter(
'sdkTunnel', 8089, httpProxyHost='vcsa',
certKeyFile='my_key_file', certFile='my_cert_file').GetConnection()
conn.request('GET', '/')
hs.assert_called_once_with('vcsa:80', cert_file='my_cert_file', key_file='my_key_file')
conn.set_tunnel.assert_called_once_with('sdkTunnel:8089')


if __name__ == '__main__':
unittest.main()

0 comments on commit aef6121

Please sign in to comment.