Skip to content
This repository was archived by the owner on May 9, 2020. It is now read-only.

Commit 5270648

Browse files
committed
Merge pull request #39 from cread/switch_to_requests
Replace urllib2 with requests, add option to disable SSL cert verification
2 parents 734e886 + 28d9501 commit 5270648

File tree

2 files changed

+16
-26
lines changed

2 files changed

+16
-26
lines changed

chef/api.py

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import six
21
import datetime
32
import logging
43
import os
54
import re
65
import socket
76
import subprocess
87
import threading
9-
import six.moves.urllib.request
10-
import six.moves.urllib.error
11-
import six.moves.urllib.parse
128
import weakref
9+
import six
1310

1411
import pkg_resources
1512

13+
import requests
14+
1615
from chef.auth import sign_request
1716
from chef.exceptions import ChefServerError
1817
from chef.rsa import Key
@@ -38,19 +37,6 @@ class UnknownRubyExpression(Exception):
3837
"""Token exception for unprocessed Ruby expressions."""
3938

4039

41-
class ChefRequest(six.moves.urllib.request.Request):
42-
"""Workaround for using PUT/DELETE with urllib2."""
43-
def __init__(self, *args, **kwargs):
44-
self._method = kwargs.pop('method', None)
45-
# Request is an old-style class, no super() allowed.
46-
six.moves.urllib.request.Request.__init__(self, *args, **kwargs)
47-
48-
def get_method(self):
49-
if self._method:
50-
return self._method
51-
return six.moves.urllib.request.Request.get_method(self)
52-
53-
5440
class ChefAPI(object):
5541
"""The ChefAPI object is a wrapper for a single Chef server.
5642
@@ -70,7 +56,7 @@ class ChefAPI(object):
7056
env_value_re = re.compile(r'ENV\[(.+)\]')
7157
ruby_string_re = re.compile(r'^\s*(["\'])(.*?)\1\s*$')
7258

73-
def __init__(self, url, key, client, version='0.10.8', headers={}):
59+
def __init__(self, url, key, client, version='0.10.8', headers={}, ssl_verify=True):
7460
self.url = url.rstrip('/')
7561
self.parsed_url = six.moves.urllib.parse.urlparse(self.url)
7662
if not isinstance(key, Key):
@@ -83,6 +69,7 @@ def __init__(self, url, key, client, version='0.10.8', headers={}):
8369
self.headers = dict((k.lower(), v) for k, v in six.iteritems(headers))
8470
self.version_parsed = pkg_resources.parse_version(self.version)
8571
self.platform = self.parsed_url.hostname == 'api.opscode.com'
72+
self.ssl_verify = ssl_verify
8673
if not api_stack_value():
8774
self.set_default()
8875

@@ -97,6 +84,7 @@ def from_config_file(cls, path):
9784
log.debug('Unable to read config file "%s"', path)
9885
return
9986
url = key_path = client_name = None
87+
ssl_verify = True
10088
for line in open(path):
10189
if not line.strip() or line.startswith('#'):
10290
continue # Skip blanks and comments
@@ -107,6 +95,10 @@ def from_config_file(cls, path):
10795
md = cls.ruby_string_re.search(value)
10896
if md:
10997
value = md.group(2)
98+
elif key == 'ssl_verify_mode':
99+
log.debug('Found ssl_verify_mode: %r', value)
100+
ssl_verify = (value.strip() != ':verify_none')
101+
log.debug('ssl_verify = %s', ssl_verify)
110102
else:
111103
# Not a string, don't even try
112104
log.debug('Value for {0} does not look like a string: {1}'.format(key, value))
@@ -137,6 +129,7 @@ def _ruby_value(match):
137129
if not os.path.isabs(key_path):
138130
# Relative paths are relative to the config file
139131
key_path = os.path.abspath(os.path.join(os.path.dirname(path), key_path))
132+
140133
if not (url and client_name and key_path):
141134
# No URL, no chance this was valid, try running Ruby
142135
log.debug('No Chef server config found, trying Ruby parse')
@@ -165,7 +158,7 @@ def _ruby_value(match):
165158
return
166159
if not client_name:
167160
client_name = socket.getfqdn()
168-
return cls(url, key_path, client_name)
161+
return cls(url, key_path, client_name, ssl_verify=ssl_verify)
169162

170163
@staticmethod
171164
def get_global():
@@ -192,11 +185,8 @@ def __exit__(self, type, value, traceback):
192185
del api_stack_value()[-1]
193186

194187
def _request(self, method, url, data, headers):
195-
# Testing hook, subclass and override for WSGI intercept
196-
if six.PY3 and data:
197-
data = data.encode()
198-
request = ChefRequest(url, data, headers, method=method)
199-
return six.moves.urllib.request.urlopen(request).read()
188+
request = requests.api.request(method, url, headers=headers, data=data, verify=self.ssl_verify)
189+
return request
200190

201191
def request(self, method, path, headers={}, data=None):
202192
auth_headers = sign_request(key=self.key, http_method=method,
@@ -228,7 +218,7 @@ def api_request(self, method, path, headers={}, data=None):
228218
headers['content-type'] = 'application/json'
229219
data = json.dumps(data)
230220
response = self.request(method, path, headers, data)
231-
return json.loads(response.decode())
221+
return response.json()
232222

233223
def __getitem__(self, path):
234224
return self.api_request('GET', path)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
'Programming Language :: Python',
3030
],
3131
zip_safe = False,
32-
install_requires = ['six>=1.9.0'],
32+
install_requires = ['six>=1.9.0','requests>=2.7.0'],
3333
tests_require = ['unittest2', 'mock'],
3434
test_suite = 'unittest2.collector',
3535
)

0 commit comments

Comments
 (0)