glance_http: add IPv6 support
Add IPv6 support when opening a socket to Glance server. Co-Authored-By: Sofer Athlan-Guyot <sathlang@redhat.com> Closes-Bug: #1557814 Change-Id: Ice966f78f94196ba31e64939df4173a67943aa43
This commit is contained in:
parent
dcc5597923
commit
f61f1fcee0
|
@ -306,13 +306,32 @@ class VerifiedHTTPSConnection(httplib.HTTPSConnection):
|
|||
|
||||
def connect(self):
|
||||
"""Connect to SSL port and apply per-connection parameters."""
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
if self.timeout is not None:
|
||||
# '0' microseconds
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO,
|
||||
struct.pack('LL', self.timeout, 0))
|
||||
self.sock = OpenSSLConnectionDelegator(self.context, sock)
|
||||
self.sock.connect((self.host, self.port))
|
||||
try:
|
||||
addresses = socket.getaddrinfo(self.host,
|
||||
self.port,
|
||||
socket.AF_UNSPEC,
|
||||
socket.SOCK_STREAM)
|
||||
except OSError as msg:
|
||||
raise exc.RestClientException(msg)
|
||||
for res in addresses:
|
||||
af, socktype, proto, canonname, sa = res
|
||||
sock = socket.socket(af, socket.SOCK_STREAM)
|
||||
|
||||
if self.timeout is not None:
|
||||
# '0' microseconds
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO,
|
||||
struct.pack('LL', self.timeout, 0))
|
||||
self.sock = OpenSSLConnectionDelegator(self.context, sock)
|
||||
try:
|
||||
self.sock.connect(sa)
|
||||
except OSError as msg:
|
||||
if self.sock:
|
||||
self.sock = None
|
||||
continue
|
||||
break
|
||||
if self.sock is None:
|
||||
# Happen only when all results have failed.
|
||||
raise exc.RestClientException('Cannot connect to %s' % self.host)
|
||||
|
||||
def close(self):
|
||||
if self.sock:
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import socket
|
||||
|
||||
import mock
|
||||
from oslotest import mockpatch
|
||||
import six
|
||||
|
@ -101,6 +103,20 @@ class TestGlanceHTTPClient(base.TestCase):
|
|||
self.assertTrue(isinstance(self.client._get_connection(),
|
||||
glance_http.VerifiedHTTPSConnection))
|
||||
|
||||
def test_get_connection_ipv4_https(self):
|
||||
endpoint = 'https://127.0.0.1'
|
||||
self.fake_auth.base_url = mock.MagicMock(return_value=endpoint)
|
||||
self.client = glance_http.HTTPClient(self.fake_auth, {})
|
||||
self.assertTrue(isinstance(self.client._get_connection(),
|
||||
glance_http.VerifiedHTTPSConnection))
|
||||
|
||||
def test_get_connection_ipv6_https(self):
|
||||
endpoint = 'https://[::1]'
|
||||
self.fake_auth.base_url = mock.MagicMock(return_value=endpoint)
|
||||
self.client = glance_http.HTTPClient(self.fake_auth, {})
|
||||
self.assertTrue(isinstance(self.client._get_connection(),
|
||||
glance_http.VerifiedHTTPSConnection))
|
||||
|
||||
def test_get_connection_url_not_fount(self):
|
||||
self.useFixture(mockpatch.PatchObject(self.client, 'connection_class',
|
||||
side_effect=httplib.InvalidURL()
|
||||
|
@ -146,6 +162,64 @@ class TestGlanceHTTPClient(base.TestCase):
|
|||
self.assertEqual(6, len(kwargs.keys()))
|
||||
|
||||
|
||||
class TestVerifiedHTTPSConnection(base.TestCase):
|
||||
|
||||
@mock.patch('socket.socket')
|
||||
@mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
|
||||
def test_connect_ipv4(self, mock_delegator, mock_socket):
|
||||
connection = glance_http.VerifiedHTTPSConnection('127.0.0.1')
|
||||
connection.connect()
|
||||
|
||||
mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
|
||||
mock_delegator.assert_called_once_with(connection.context,
|
||||
mock_socket.return_value)
|
||||
mock_delegator.return_value.connect.assert_called_once_with(
|
||||
(connection.host, 443))
|
||||
|
||||
@mock.patch('socket.socket')
|
||||
@mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
|
||||
def test_connect_ipv6(self, mock_delegator, mock_socket):
|
||||
connection = glance_http.VerifiedHTTPSConnection('[::1]')
|
||||
connection.connect()
|
||||
|
||||
mock_socket.assert_called_once_with(socket.AF_INET6,
|
||||
socket.SOCK_STREAM)
|
||||
mock_delegator.assert_called_once_with(connection.context,
|
||||
mock_socket.return_value)
|
||||
mock_delegator.return_value.connect.assert_called_once_with(
|
||||
(connection.host, 443, 0, 0))
|
||||
|
||||
@mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
|
||||
@mock.patch('socket.getaddrinfo',
|
||||
side_effect=OSError('Gettaddrinfo failed'))
|
||||
def test_connect_with_address_lookup_failure(self, mock_getaddrinfo,
|
||||
mock_delegator):
|
||||
connection = glance_http.VerifiedHTTPSConnection('127.0.0.1')
|
||||
self.assertRaises(exceptions.RestClientException, connection.connect)
|
||||
|
||||
mock_getaddrinfo.assert_called_once_with(
|
||||
connection.host, connection.port, 0, socket.SOCK_STREAM)
|
||||
|
||||
@mock.patch('socket.socket')
|
||||
@mock.patch('socket.getaddrinfo',
|
||||
return_value=[(2, 1, 6, '', ('127.0.0.1', 443))])
|
||||
@mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
|
||||
def test_connect_with_socket_failure(self, mock_delegator,
|
||||
mock_getaddrinfo,
|
||||
mock_socket):
|
||||
mock_delegator.return_value.connect.side_effect = \
|
||||
OSError('Connect failed')
|
||||
|
||||
connection = glance_http.VerifiedHTTPSConnection('127.0.0.1')
|
||||
self.assertRaises(exceptions.RestClientException, connection.connect)
|
||||
|
||||
mock_getaddrinfo.assert_called_once_with(
|
||||
connection.host, connection.port, 0, socket.SOCK_STREAM)
|
||||
mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
|
||||
mock_delegator.return_value.connect.\
|
||||
assert_called_once_with((connection.host, 443))
|
||||
|
||||
|
||||
class TestResponseBodyIterator(base.TestCase):
|
||||
|
||||
def test_iter_default_chunk_size_64k(self):
|
||||
|
|
Loading…
Reference in New Issue