requests raises IOError on missing cacert file

Bug #1692085 reported by Eric Fried
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Glance Client
Fix Released
Undecided
Eric Fried

Bug Description

This requests commit [1] changed the behavior when a nonexistent cacert file is passed in, causing the glanceclient unit test at [2] to start failing.

[1] https://github.com/kennethreitz/requests/commit/7d8b87c37f3a5fb993fd83eda6888ac217cd108e
[2] https://github.com/openstack/python-glanceclient/blob/a0edf0c2bfb7bcc8253aaf46f6a67607e9b09048/glanceclient/tests/unit/test_ssl.py#L242

PY2:
======================================================================
FAIL: glanceclient.tests.unit.test_ssl.TestHTTPSVerifyCert.test_v2_requests_bad_ca
tags: worker-0
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/stack/python-glanceclient/.tox/py27/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "glanceclient/tests/unit/test_ssl.py", line 264, in test_v2_requests_bad_ca
    self.fail('Unexpected exception has been raised')
  File "/opt/stack/python-glanceclient/.tox/py27/local/lib/python2.7/site-packages/unittest2/case.py", line 690, in fail
    raise self.failureException(msg)
AssertionError: Unexpected exception has been raised
======================================================================

The actual exception here is:
======================================================================
Traceback (most recent call last):
  File "/opt/stack/python-glanceclient/.tox/py27/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "glanceclient/tests/unit/test_ssl.py", line 253, in test_v2_requests_bad_ca
    gc.images.get('image123')
  File "glanceclient/v2/images.py", line 197, in get
    return self._get(image_id)
  File "glanceclient/common/utils.py", line 535, in inner
    return RequestIdProxy(wrapped(*args, **kwargs))
  File "glanceclient/v2/images.py", line 190, in _get
    resp, body = self.http_client.get(url, headers=header)
  File "glanceclient/common/http.py", line 284, in get
    return self._request('GET', url, **kwargs)
  File "glanceclient/common/http.py", line 247, in _request
    **kwargs)
  File "/opt/stack/python-glanceclient/.tox/py27/local/lib/python2.7/site-packages/requests/sessions.py", line 518, in request
    resp = self.send(prep, **send_kwargs)
  File "/opt/stack/python-glanceclient/.tox/py27/local/lib/python2.7/site-packages/requests/sessions.py", line 639, in send
    r = adapter.send(request, **kwargs)
  File "/opt/stack/python-glanceclient/.tox/py27/local/lib/python2.7/site-packages/requests/adapters.py", line 405, in send
    self.cert_verify(conn, request.url, verify, cert)
  File "/opt/stack/python-glanceclient/.tox/py27/local/lib/python2.7/site-packages/requests/adapters.py", line 225, in cert_verify
    "invalid path: {0}".format(cert_loc))
IOError: Could not find a suitable TLS CA certificate bundle, invalid path: /opt/stack/python-glanceclient/glanceclient/tests/unit/var/badca.crt
======================================================================

PY3:
======================================================================
FAIL: glanceclient.tests.unit.test_ssl.TestHTTPSVerifyCert.test_v2_requests_bad_ca
tags: worker-0
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/stack/python-glanceclient/glanceclient/common/http.py", line 247, in _request
    **kwargs)
  File "/opt/stack/python-glanceclient/.tox/py35/lib/python3.5/site-packages/requests/sessions.py", line 518, in request
    resp = self.send(prep, **send_kwargs)
  File "/opt/stack/python-glanceclient/.tox/py35/lib/python3.5/site-packages/requests/sessions.py", line 639, in send
    r = adapter.send(request, **kwargs)
  File "/opt/stack/python-glanceclient/.tox/py35/lib/python3.5/site-packages/requests/adapters.py", line 405, in send
    self.cert_verify(conn, request.url, verify, cert)
  File "/opt/stack/python-glanceclient/.tox/py35/lib/python3.5/site-packages/requests/adapters.py", line 225, in cert_verify
    "invalid path: {0}".format(cert_loc))
OSError: Could not find a suitable TLS CA certificate bundle, invalid path: /opt/stack/python-glanceclient/glanceclient/tests/unit/var/badca.crt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/stack/python-glanceclient/glanceclient/tests/unit/test_ssl.py", line 253, in test_v2_requests_bad_ca
    gc.images.get('image123')
  File "/opt/stack/python-glanceclient/glanceclient/v2/images.py", line 197, in get
    return self._get(image_id)
  File "/opt/stack/python-glanceclient/glanceclient/common/utils.py", line 535, in inner
    return RequestIdProxy(wrapped(*args, **kwargs))
  File "/opt/stack/python-glanceclient/glanceclient/v2/images.py", line 190, in _get
    resp, body = self.http_client.get(url, headers=header)
  File "/opt/stack/python-glanceclient/glanceclient/common/http.py", line 284, in get
    return self._request('GET', url, **kwargs)
  File "/opt/stack/python-glanceclient/glanceclient/common/http.py", line 264, in _request
    raise exc.CommunicationError(message=message)
glanceclient.exc.CommunicationError: Error communicating with https://0.0.0.0:32850 Could not find a suitable TLS CA certificate bundle, invalid path: /opt/stack/python-glanceclient/glanceclient/tests/unit/var/badca.crt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/stack/python-glanceclient/.tox/py35/lib/python3.5/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/opt/stack/python-glanceclient/glanceclient/tests/unit/test_ssl.py", line 262, in test_v2_requests_bad_ca
    self.fail('No appropriate failure message is received')
  File "/opt/stack/python-glanceclient/.tox/py35/lib/python3.5/site-packages/unittest2/case.py", line 690, in fail
    raise self.failureException(msg)
AssertionError: No appropriate failure message is received
======================================================================

That is, in PY2, the IOError is coming through; but somehow in PY3, it's getting converted to CommunicationError - haven't fully figured that one out yet.

However, the solution will likely at least include adding IOError to the list of caught-and-converted exceptions in the neighborhood of [3]; and also changing the criteria being used by the test case around [4].

IMO, we should not be parsing exception text - that way lies madness. Further, to make failures easier to diagnose, the test case should simply raise when the exception isn't as expected.

[3] https://github.com/openstack/python-glanceclient/blob/a0edf0c2bfb7bcc8253aaf46f6a67607e9b09048/glanceclient/common/http.py#L248-L264
[4] https://github.com/openstack/python-glanceclient/blob/a0edf0c2bfb7bcc8253aaf46f6a67607e9b09048/glanceclient/tests/unit/test_ssl.py#L259-L264

Revision history for this message
Eric Fried (efried) wrote :
Changed in python-glanceclient:
assignee: nobody → Eric Fried (efried)
status: New → In Progress
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix merged to python-glanceclient (master)

Reviewed: https://review.openstack.org/466385
Committed: https://git.openstack.org/cgit/openstack/python-glanceclient/commit/?id=7df87fd4a26ebee3899fbc42d21757bf880a10d4
Submitter: Jenkins
Branch: master

commit 7df87fd4a26ebee3899fbc42d21757bf880a10d4
Author: Eric Fried <email address hidden>
Date: Fri May 19 14:53:34 2017 -0400

    Convert IOError from requests

    This requests commit [1] changed the behavior when a nonexistent cacert
    file is passed in: now it raises IOError. This is getting through
    glanceclient.common.http.HTTPClient._request, which used to raise
    CommunicationError in this scenario.

    Even though there is arguably a better exception than CommunicationError
    to represent this condition (like maybe IOError), for backward
    compatibility this change set converts IOError to CommunicationError.

    We also improve the unit test to raise the original exception if the
    expected conditions aren't met; this improves debugability.

    [1] https://github.com/kennethreitz/requests/commit/7d8b87c37f3a5fb993fd83eda6888ac217cd108e

    Change-Id: I6a2cf4c6d041b67d3509153b4cef18b459263648
    Closes-Bug: #1692085

Changed in python-glanceclient:
status: In Progress → Fix Released
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix included in openstack/python-glanceclient 2.7.0

This issue was fixed in the openstack/python-glanceclient 2.7.0 release.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.