Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / __init__.py @ f7a37648

History | View | Annotate | Download (14.7 kB)

1 43ca98ee Giorgos Verigakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 a1c50326 Giorgos Verigakis
#
3 a1c50326 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 a1c50326 Giorgos Verigakis
# without modification, are permitted provided that the following
5 a1c50326 Giorgos Verigakis
# conditions are met:
6 a1c50326 Giorgos Verigakis
#
7 a1c50326 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 e742badc Stavros Sachtouris
#      copyright notice, self.list of conditions and the following
9 a1c50326 Giorgos Verigakis
#      disclaimer.
10 a1c50326 Giorgos Verigakis
#
11 a1c50326 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 e742badc Stavros Sachtouris
#      copyright notice, self.list of conditions and the following
13 a1c50326 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 a1c50326 Giorgos Verigakis
#      provided with the distribution.
15 a1c50326 Giorgos Verigakis
#
16 a1c50326 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 a1c50326 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 a1c50326 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 a1c50326 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 a1c50326 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 a1c50326 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 a1c50326 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 a1c50326 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 a1c50326 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 a1c50326 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 a1c50326 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 a1c50326 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 a1c50326 Giorgos Verigakis
#
29 a1c50326 Giorgos Verigakis
# The views and conclusions contained in the software and
30 a1c50326 Giorgos Verigakis
# documentation are those of the authors and should not be
31 a1c50326 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 a1c50326 Giorgos Verigakis
# or implied, of GRNET S.A.
33 a1c50326 Giorgos Verigakis
34 fce31e83 Stavros Sachtouris
from urllib2 import quote
35 c2b5da2f Stavros Sachtouris
from urlparse import urlparse
36 2b74ab4a Stavros Sachtouris
from threading import Thread
37 de4f08ef Stavros Sachtouris
from json import dumps, loads
38 cad39033 Stavros Sachtouris
from time import time
39 c2b5da2f Stavros Sachtouris
from httplib import ResponseNotReady
40 c2b5da2f Stavros Sachtouris
from time import sleep
41 c2b5da2f Stavros Sachtouris
from random import random
42 c4d51ec9 Stavros Sachtouris
from logging import getLogger
43 c2b5da2f Stavros Sachtouris
44 c2b5da2f Stavros Sachtouris
from objpool.http import PooledHTTPConnection
45 61ca0ecd Stavros Sachtouris
46 6a0b1658 Giorgos Verigakis
47 21871fb2 Stavros Sachtouris
TIMEOUT = 60.0   # seconds
48 21871fb2 Stavros Sachtouris
HTTP_METHODS = ['GET', 'POST', 'PUT', 'HEAD', 'DELETE', 'COPY', 'MOVE']
49 2406db97 Stavros Sachtouris
50 c4d51ec9 Stavros Sachtouris
log = getLogger(__name__)
51 c4d51ec9 Stavros Sachtouris
sendlog = getLogger('%s.send' % __name__)
52 c4d51ec9 Stavros Sachtouris
recvlog = getLogger('%s.recv' % __name__)
53 e8af27f4 Stavros Sachtouris
54 c2b5da2f Stavros Sachtouris
55 c2b5da2f Stavros Sachtouris
def _encode(v):
56 c2b5da2f Stavros Sachtouris
    if v and isinstance(v, unicode):
57 c2b5da2f Stavros Sachtouris
        return quote(v.encode('utf-8'))
58 c2b5da2f Stavros Sachtouris
    return v
59 c2b5da2f Stavros Sachtouris
60 3dabe5d2 Stavros Sachtouris
61 a1c50326 Giorgos Verigakis
class ClientError(Exception):
62 4f989909 Stavros Sachtouris
    def __init__(self, message, status=0, details=None):
63 e9db8806 Stavros Sachtouris
        log.debug('ClientError: msg[%s], sts[%s], dtl[%s]' % (
64 008a5db5 Stavros Sachtouris
            message,
65 008a5db5 Stavros Sachtouris
            status,
66 008a5db5 Stavros Sachtouris
            details))
67 de4f08ef Stavros Sachtouris
        try:
68 1f417830 Stavros Sachtouris
            message += '' if message and message[-1] == '\n' else '\n'
69 062b1d0a Stavros Sachtouris
            serv_stat, sep, new_msg = message.partition('{')
70 f4de4c91 Stavros Sachtouris
            new_msg = sep + new_msg[:-1 if new_msg.endswith('\n') else 0]
71 062b1d0a Stavros Sachtouris
            json_msg = loads(new_msg)
72 de4f08ef Stavros Sachtouris
            key = json_msg.keys()[0]
73 f4de4c91 Stavros Sachtouris
            serv_stat = serv_stat.strip()
74 062b1d0a Stavros Sachtouris
75 de4f08ef Stavros Sachtouris
            json_msg = json_msg[key]
76 f4de4c91 Stavros Sachtouris
            message = '%s %s (%s)\n' % (
77 f4de4c91 Stavros Sachtouris
                serv_stat,
78 f4de4c91 Stavros Sachtouris
                key,
79 f4de4c91 Stavros Sachtouris
                json_msg['message']) if (
80 f4de4c91 Stavros Sachtouris
                    'message' in json_msg) else '%s %s' % (serv_stat, key)
81 f4de4c91 Stavros Sachtouris
            status = json_msg.get('code', status)
82 de4f08ef Stavros Sachtouris
            if 'details' in json_msg:
83 de4f08ef Stavros Sachtouris
                if not details:
84 de4f08ef Stavros Sachtouris
                    details = []
85 f4de4c91 Stavros Sachtouris
                if not isinstance(details, list):
86 de4f08ef Stavros Sachtouris
                    details = [details]
87 de4f08ef Stavros Sachtouris
                if json_msg['details']:
88 de4f08ef Stavros Sachtouris
                    details.append(json_msg['details'])
89 f4de4c91 Stavros Sachtouris
        except Exception:
90 de4f08ef Stavros Sachtouris
            pass
91 f4de4c91 Stavros Sachtouris
        finally:
92 5dde4c83 Stavros Sachtouris
            while message.endswith('\n\n'):
93 5dde4c83 Stavros Sachtouris
                message = message[:-1]
94 f4de4c91 Stavros Sachtouris
            super(ClientError, self).__init__(message)
95 f4de4c91 Stavros Sachtouris
            self.status = status if isinstance(status, int) else 0
96 f4de4c91 Stavros Sachtouris
            self.details = details if details else []
97 a1c50326 Giorgos Verigakis
98 3dabe5d2 Stavros Sachtouris
99 5fdccdec Stavros Sachtouris
class Logged(object):
100 5fdccdec Stavros Sachtouris
101 5fdccdec Stavros Sachtouris
    LOG_TOKEN = False
102 5fdccdec Stavros Sachtouris
    LOG_DATA = False
103 5fdccdec Stavros Sachtouris
104 5fdccdec Stavros Sachtouris
105 5fdccdec Stavros Sachtouris
class RequestManager(Logged):
106 c2b5da2f Stavros Sachtouris
    """Handle http request information"""
107 c2b5da2f Stavros Sachtouris
108 c2b5da2f Stavros Sachtouris
    def _connection_info(self, url, path, params={}):
109 c2b5da2f Stavros Sachtouris
        """ Set self.url to scheme://netloc/?params
110 c2b5da2f Stavros Sachtouris
        :param url: (str or unicode) The service url
111 c2b5da2f Stavros Sachtouris

112 c2b5da2f Stavros Sachtouris
        :param path: (str or unicode) The service path (url/path)
113 c2b5da2f Stavros Sachtouris

114 c2b5da2f Stavros Sachtouris
        :param params: (dict) Parameters to add to final url
115 c2b5da2f Stavros Sachtouris

116 c2b5da2f Stavros Sachtouris
        :returns: (scheme, netloc)
117 c2b5da2f Stavros Sachtouris
        """
118 c2b5da2f Stavros Sachtouris
        url = _encode(url) if url else 'http://127.0.0.1/'
119 c2b5da2f Stavros Sachtouris
        url += '' if url.endswith('/') else '/'
120 c2b5da2f Stavros Sachtouris
        if path:
121 c2b5da2f Stavros Sachtouris
            url += _encode(path[1:] if path.startswith('/') else path)
122 7fa5c263 Stavros Sachtouris
        delim = '?'
123 7fa5c263 Stavros Sachtouris
        for key, val in params.items():
124 c2b5da2f Stavros Sachtouris
            val = _encode(val)
125 7fa5c263 Stavros Sachtouris
            url += '%s%s%s' % (delim, key, ('=%s' % val) if val else '')
126 7fa5c263 Stavros Sachtouris
            delim = '&'
127 c2b5da2f Stavros Sachtouris
        parsed = urlparse(url)
128 c2b5da2f Stavros Sachtouris
        self.url = url
129 c2b5da2f Stavros Sachtouris
        self.path = parsed.path or '/'
130 c2b5da2f Stavros Sachtouris
        if parsed.query:
131 c2b5da2f Stavros Sachtouris
            self.path += '?%s' % parsed.query
132 c2b5da2f Stavros Sachtouris
        return (parsed.scheme, parsed.netloc)
133 c2b5da2f Stavros Sachtouris
134 c2b5da2f Stavros Sachtouris
    def __init__(
135 c2b5da2f Stavros Sachtouris
            self, method, url, path,
136 c2b5da2f Stavros Sachtouris
            data=None, headers={}, params={}):
137 c2b5da2f Stavros Sachtouris
        method = method.upper()
138 c2b5da2f Stavros Sachtouris
        assert method in HTTP_METHODS, 'Invalid http method %s' % method
139 c2b5da2f Stavros Sachtouris
        if headers:
140 c2b5da2f Stavros Sachtouris
            assert isinstance(headers, dict)
141 7fa5c263 Stavros Sachtouris
        self.headers = dict(headers)
142 c2b5da2f Stavros Sachtouris
        self.method, self.data = method, data
143 c2b5da2f Stavros Sachtouris
        self.scheme, self.netloc = self._connection_info(url, path, params)
144 c2b5da2f Stavros Sachtouris
145 c4563114 Stavros Sachtouris
    def dump_log(self):
146 5fdccdec Stavros Sachtouris
        sendlog.info('%s %s://%s%s\t[%s]' % (
147 34b88989 Stavros Sachtouris
            self.method,
148 34b88989 Stavros Sachtouris
            self.scheme,
149 34b88989 Stavros Sachtouris
            self.netloc,
150 34b88989 Stavros Sachtouris
            self.path,
151 34b88989 Stavros Sachtouris
            self))
152 21871fb2 Stavros Sachtouris
        for key, val in self.headers.items():
153 5fdccdec Stavros Sachtouris
            if (not self.LOG_TOKEN) and key.lower() == 'x-auth-token':
154 21871fb2 Stavros Sachtouris
                continue
155 5fdccdec Stavros Sachtouris
            sendlog.info('  %s: %s\t[%s]' % (key, val, self))
156 21871fb2 Stavros Sachtouris
        if self.data:
157 5fdccdec Stavros Sachtouris
            sendlog.info('data size:%s\t[%s]' % (len(self.data), self))
158 5fdccdec Stavros Sachtouris
            if self.LOG_DATA:
159 e9db8806 Stavros Sachtouris
                sendlog.info(self.data)
160 21871fb2 Stavros Sachtouris
        else:
161 5fdccdec Stavros Sachtouris
            sendlog.info('data size:0\t[%s]' % self)
162 34b88989 Stavros Sachtouris
        sendlog.info('')
163 21871fb2 Stavros Sachtouris
164 c2b5da2f Stavros Sachtouris
    def perform(self, conn):
165 c2b5da2f Stavros Sachtouris
        """
166 c2b5da2f Stavros Sachtouris
        :param conn: (httplib connection object)
167 c2b5da2f Stavros Sachtouris

168 c2b5da2f Stavros Sachtouris
        :returns: (HTTPResponse)
169 c2b5da2f Stavros Sachtouris
        """
170 c2b5da2f Stavros Sachtouris
        conn.request(
171 c2b5da2f Stavros Sachtouris
            method=str(self.method.upper()),
172 c2b5da2f Stavros Sachtouris
            url=str(self.path),
173 c2b5da2f Stavros Sachtouris
            headers=self.headers,
174 c2b5da2f Stavros Sachtouris
            body=self.data)
175 c4563114 Stavros Sachtouris
        self.dump_log()
176 f47417e7 Stavros Sachtouris
        keep_trying = TIMEOUT
177 f8eea8ec Stavros Sachtouris
        while keep_trying > 0:
178 c2b5da2f Stavros Sachtouris
            try:
179 c2b5da2f Stavros Sachtouris
                return conn.getresponse()
180 c2b5da2f Stavros Sachtouris
            except ResponseNotReady:
181 f8eea8ec Stavros Sachtouris
                wait = 0.03 * random()
182 f8eea8ec Stavros Sachtouris
                sleep(wait)
183 f8eea8ec Stavros Sachtouris
                keep_trying -= wait
184 21871fb2 Stavros Sachtouris
        logmsg = 'Kamaki Timeout %s %s\t[%s]' % (self.method, self.path, self)
185 34b88989 Stavros Sachtouris
        recvlog.debug(logmsg)
186 f8eea8ec Stavros Sachtouris
        raise ClientError('HTTPResponse takes too long - kamaki timeout')
187 c2b5da2f Stavros Sachtouris
188 c2b5da2f Stavros Sachtouris
189 5fdccdec Stavros Sachtouris
class ResponseManager(Logged):
190 c2b5da2f Stavros Sachtouris
    """Manage the http request and handle the response data, headers, etc."""
191 c2b5da2f Stavros Sachtouris
192 c2b5da2f Stavros Sachtouris
    def __init__(self, request, poolsize=None):
193 c2b5da2f Stavros Sachtouris
        """
194 c2b5da2f Stavros Sachtouris
        :param request: (RequestManager)
195 c2b5da2f Stavros Sachtouris
        """
196 c2b5da2f Stavros Sachtouris
        self.request = request
197 c2b5da2f Stavros Sachtouris
        self._request_performed = False
198 c2b5da2f Stavros Sachtouris
        self.poolsize = poolsize
199 c2b5da2f Stavros Sachtouris
200 c2b5da2f Stavros Sachtouris
    def _get_response(self):
201 c2b5da2f Stavros Sachtouris
        if self._request_performed:
202 c2b5da2f Stavros Sachtouris
            return
203 c2b5da2f Stavros Sachtouris
204 c2b5da2f Stavros Sachtouris
        pool_kw = dict(size=self.poolsize) if self.poolsize else dict()
205 c2b5da2f Stavros Sachtouris
        try:
206 c2b5da2f Stavros Sachtouris
            with PooledHTTPConnection(
207 c2b5da2f Stavros Sachtouris
                    self.request.netloc, self.request.scheme,
208 c2b5da2f Stavros Sachtouris
                    **pool_kw) as connection:
209 5fdccdec Stavros Sachtouris
                self.request.LOG_TOKEN = self.LOG_TOKEN
210 5fdccdec Stavros Sachtouris
                self.request.LOG_DATA = self.LOG_DATA
211 c2b5da2f Stavros Sachtouris
                r = self.request.perform(connection)
212 005d3f25 Stavros Sachtouris
                recvlog.info('\n%s <-- %s <-- [req: %s]\n' % (
213 005d3f25 Stavros Sachtouris
                    self, r, self.request))
214 c2b5da2f Stavros Sachtouris
                self._request_performed = True
215 008a5db5 Stavros Sachtouris
                self._status_code, self._status = r.status, r.reason
216 5fdccdec Stavros Sachtouris
                recvlog.info(
217 008a5db5 Stavros Sachtouris
                    '%d %s\t[p: %s]' % (self.status_code, self.status, self))
218 c2b5da2f Stavros Sachtouris
                self._headers = dict()
219 c2b5da2f Stavros Sachtouris
                for k, v in r.getheaders():
220 5fdccdec Stavros Sachtouris
                    if (not self.LOG_TOKEN) and k.lower() == 'x-auth-token':
221 008a5db5 Stavros Sachtouris
                        continue
222 34b88989 Stavros Sachtouris
                    self._headers[k] = v
223 5fdccdec Stavros Sachtouris
                    recvlog.info('  %s: %s\t[p: %s]' % (k, v, self))
224 c2b5da2f Stavros Sachtouris
                self._content = r.read()
225 5fdccdec Stavros Sachtouris
                recvlog.info('data size: %s\t[p: %s]' % (
226 34b88989 Stavros Sachtouris
                    len(self._content) if self._content else 0,
227 34b88989 Stavros Sachtouris
                    self))
228 5fdccdec Stavros Sachtouris
                if self.LOG_DATA and self._content:
229 e9db8806 Stavros Sachtouris
                    recvlog.info('%s\t[p: %s]' % (self._content, self))
230 c2b5da2f Stavros Sachtouris
        except Exception as err:
231 c2b5da2f Stavros Sachtouris
            from traceback import format_stack
232 c2b5da2f Stavros Sachtouris
            recvlog.debug('\n'.join(['%s' % type(err)] + format_stack()))
233 c2b5da2f Stavros Sachtouris
            raise ClientError(
234 c2b5da2f Stavros Sachtouris
                'Failed while http-connecting to %s (%s)' % (
235 c2b5da2f Stavros Sachtouris
                    self.request.url,
236 f8eea8ec Stavros Sachtouris
                    err))
237 c2b5da2f Stavros Sachtouris
238 c2b5da2f Stavros Sachtouris
    @property
239 c2b5da2f Stavros Sachtouris
    def status_code(self):
240 c2b5da2f Stavros Sachtouris
        self._get_response()
241 c2b5da2f Stavros Sachtouris
        return self._status_code
242 c2b5da2f Stavros Sachtouris
243 c2b5da2f Stavros Sachtouris
    @property
244 c2b5da2f Stavros Sachtouris
    def status(self):
245 c2b5da2f Stavros Sachtouris
        self._get_response()
246 c2b5da2f Stavros Sachtouris
        return self._status
247 c2b5da2f Stavros Sachtouris
248 c2b5da2f Stavros Sachtouris
    @property
249 c2b5da2f Stavros Sachtouris
    def headers(self):
250 c2b5da2f Stavros Sachtouris
        self._get_response()
251 c2b5da2f Stavros Sachtouris
        return self._headers
252 c2b5da2f Stavros Sachtouris
253 c2b5da2f Stavros Sachtouris
    @property
254 c2b5da2f Stavros Sachtouris
    def content(self):
255 c2b5da2f Stavros Sachtouris
        self._get_response()
256 c2b5da2f Stavros Sachtouris
        return self._content
257 c2b5da2f Stavros Sachtouris
258 c2b5da2f Stavros Sachtouris
    @property
259 c2b5da2f Stavros Sachtouris
    def text(self):
260 c2b5da2f Stavros Sachtouris
        """
261 c2b5da2f Stavros Sachtouris
        :returns: (str) content
262 c2b5da2f Stavros Sachtouris
        """
263 c2b5da2f Stavros Sachtouris
        self._get_response()
264 c2b5da2f Stavros Sachtouris
        return '%s' % self._content
265 c2b5da2f Stavros Sachtouris
266 c2b5da2f Stavros Sachtouris
    @property
267 c2b5da2f Stavros Sachtouris
    def json(self):
268 c2b5da2f Stavros Sachtouris
        """
269 c2b5da2f Stavros Sachtouris
        :returns: (dict) squeezed from json-formated content
270 c2b5da2f Stavros Sachtouris
        """
271 c2b5da2f Stavros Sachtouris
        self._get_response()
272 c2b5da2f Stavros Sachtouris
        try:
273 c2b5da2f Stavros Sachtouris
            return loads(self._content)
274 c2b5da2f Stavros Sachtouris
        except ValueError as err:
275 f8eea8ec Stavros Sachtouris
            raise ClientError('Response not formated in JSON - %s' % err)
276 c2b5da2f Stavros Sachtouris
277 c2b5da2f Stavros Sachtouris
278 2b74ab4a Stavros Sachtouris
class SilentEvent(Thread):
279 34b88989 Stavros Sachtouris
    """Thread-run method(*args, **kwargs)"""
280 2b74ab4a Stavros Sachtouris
    def __init__(self, method, *args, **kwargs):
281 2b74ab4a Stavros Sachtouris
        super(self.__class__, self).__init__()
282 2b74ab4a Stavros Sachtouris
        self.method = method
283 2b74ab4a Stavros Sachtouris
        self.args = args
284 2b74ab4a Stavros Sachtouris
        self.kwargs = kwargs
285 2b74ab4a Stavros Sachtouris
286 2b74ab4a Stavros Sachtouris
    @property
287 2b74ab4a Stavros Sachtouris
    def exception(self):
288 2b74ab4a Stavros Sachtouris
        return getattr(self, '_exception', False)
289 2b74ab4a Stavros Sachtouris
290 2b74ab4a Stavros Sachtouris
    @property
291 2b74ab4a Stavros Sachtouris
    def value(self):
292 2b74ab4a Stavros Sachtouris
        return getattr(self, '_value', None)
293 2b74ab4a Stavros Sachtouris
294 2b74ab4a Stavros Sachtouris
    def run(self):
295 2b74ab4a Stavros Sachtouris
        try:
296 2b74ab4a Stavros Sachtouris
            self._value = self.method(*(self.args), **(self.kwargs))
297 2b74ab4a Stavros Sachtouris
        except Exception as e:
298 7644c38e Stavros Sachtouris
            recvlog.debug('Thread %s got exception %s\n<%s %s' % (
299 7644c38e Stavros Sachtouris
                self,
300 7644c38e Stavros Sachtouris
                type(e),
301 7644c38e Stavros Sachtouris
                e.status if isinstance(e, ClientError) else '',
302 7644c38e Stavros Sachtouris
                e))
303 2b74ab4a Stavros Sachtouris
            self._exception = e
304 2b74ab4a Stavros Sachtouris
305 6069b53b Stavros Sachtouris
306 6a0b1658 Giorgos Verigakis
class Client(object):
307 cad39033 Stavros Sachtouris
308 34b88989 Stavros Sachtouris
    MAX_THREADS = 7
309 34b88989 Stavros Sachtouris
    DATE_FORMATS = [
310 34b88989 Stavros Sachtouris
        '%a %b %d %H:%M:%S %Y',
311 34b88989 Stavros Sachtouris
        '%A, %d-%b-%y %H:%M:%S GMT',
312 34b88989 Stavros Sachtouris
        '%a, %d %b %Y %H:%M:%S GMT']
313 5fdccdec Stavros Sachtouris
    LOG_TOKEN = False
314 5fdccdec Stavros Sachtouris
    LOG_DATA = False
315 34b88989 Stavros Sachtouris
316 c2b5da2f Stavros Sachtouris
    def __init__(self, base_url, token):
317 6a0b1658 Giorgos Verigakis
        self.base_url = base_url
318 6c62a96d Giorgos Verigakis
        self.token = token
319 c2b5da2f Stavros Sachtouris
        self.headers, self.params = dict(), dict()
320 6c62a96d Giorgos Verigakis
321 cad39033 Stavros Sachtouris
    def _init_thread_limit(self, limit=1):
322 9c6c3d69 Stavros Sachtouris
        assert isinstance(limit, int) and limit > 0, 'Thread limit not a +int'
323 cad39033 Stavros Sachtouris
        self._thread_limit = limit
324 cad39033 Stavros Sachtouris
        self._elapsed_old = 0.0
325 cad39033 Stavros Sachtouris
        self._elapsed_new = 0.0
326 cad39033 Stavros Sachtouris
327 cad39033 Stavros Sachtouris
    def _watch_thread_limit(self, threadlist):
328 9c6c3d69 Stavros Sachtouris
        self._thread_limit = getattr(self, '_thread_limit', 1)
329 9c6c3d69 Stavros Sachtouris
        self._elapsed_new = getattr(self, '_elapsed_new', 0.0)
330 9c6c3d69 Stavros Sachtouris
        self._elapsed_old = getattr(self, '_elapsed_old', 0.0)
331 16c895db Stavros Sachtouris
        recvlog.debug('# running threads: %s' % len(threadlist))
332 9c6c3d69 Stavros Sachtouris
        if self._elapsed_old and self._elapsed_old >= self._elapsed_new and (
333 16b0afe6 Stavros Sachtouris
                self._thread_limit < self.MAX_THREADS):
334 2005b18e Stavros Sachtouris
            self._thread_limit += 1
335 9c6c3d69 Stavros Sachtouris
        elif self._elapsed_old <= self._elapsed_new and self._thread_limit > 1:
336 cad39033 Stavros Sachtouris
            self._thread_limit -= 1
337 cad39033 Stavros Sachtouris
338 cad39033 Stavros Sachtouris
        self._elapsed_old = self._elapsed_new
339 cad39033 Stavros Sachtouris
        if len(threadlist) >= self._thread_limit:
340 cad39033 Stavros Sachtouris
            self._elapsed_new = 0.0
341 cad39033 Stavros Sachtouris
            for thread in threadlist:
342 cad39033 Stavros Sachtouris
                begin_time = time()
343 cad39033 Stavros Sachtouris
                thread.join()
344 cad39033 Stavros Sachtouris
                self._elapsed_new += time() - begin_time
345 cad39033 Stavros Sachtouris
            self._elapsed_new = self._elapsed_new / len(threadlist)
346 cad39033 Stavros Sachtouris
            return []
347 cad39033 Stavros Sachtouris
        return threadlist
348 cad39033 Stavros Sachtouris
349 6ad245d5 Stavros Sachtouris
    def _raise_for_status(self, r):
350 e9db8806 Stavros Sachtouris
        log.debug('raise err from [%s] of type[%s]' % (r, type(r)))
351 5dde4c83 Stavros Sachtouris
        status_msg = getattr(r, 'status', None) or ''
352 d804de82 Stavros Sachtouris
        try:
353 7966ffb8 Stavros Sachtouris
            message = '%s %s\n' % (status_msg, r.text)
354 d804de82 Stavros Sachtouris
        except:
355 7966ffb8 Stavros Sachtouris
            message = '%s %s\n' % (status_msg, r)
356 7966ffb8 Stavros Sachtouris
        status = getattr(r, 'status_code', getattr(r, 'status', 0))
357 7966ffb8 Stavros Sachtouris
        raise ClientError(message, status=status)
358 6a0b1658 Giorgos Verigakis
359 4adfa919 Stavros Sachtouris
    def set_header(self, name, value, iff=True):
360 3dabe5d2 Stavros Sachtouris
        """Set a header 'name':'value'"""
361 4adfa919 Stavros Sachtouris
        if value is not None and iff:
362 c2b5da2f Stavros Sachtouris
            self.headers[name] = value
363 2f749e6e Stavros Sachtouris
364 2f749e6e Stavros Sachtouris
    def set_param(self, name, value=None, iff=True):
365 2f749e6e Stavros Sachtouris
        if iff:
366 c2b5da2f Stavros Sachtouris
            self.params[name] = value
367 2f749e6e Stavros Sachtouris
368 de73876b Stavros Sachtouris
    def request(
369 c2b5da2f Stavros Sachtouris
            self, method, path,
370 c2b5da2f Stavros Sachtouris
            async_headers=dict(), async_params=dict(),
371 24ff0a35 Stavros Sachtouris
            **kwargs):
372 34b88989 Stavros Sachtouris
        """Commit an HTTP request to base_url/path
373 34b88989 Stavros Sachtouris
        Requests are commited to and performed by Request/ResponseManager
374 34b88989 Stavros Sachtouris
        These classes perform a lazy http request. Present method, by default,
375 34b88989 Stavros Sachtouris
        enforces them to perform the http call. Hint: call present method with
376 34b88989 Stavros Sachtouris
        success=None to get a non-performed ResponseManager object.
377 34b88989 Stavros Sachtouris
        """
378 6a6175c0 Stavros Sachtouris
        assert isinstance(method, str) or isinstance(method, unicode)
379 6a6175c0 Stavros Sachtouris
        assert method
380 6a6175c0 Stavros Sachtouris
        assert isinstance(path, str) or isinstance(path, unicode)
381 d726b3d0 Stavros Sachtouris
        try:
382 c2b5da2f Stavros Sachtouris
            headers = dict(self.headers)
383 c2b5da2f Stavros Sachtouris
            headers.update(async_headers)
384 c2b5da2f Stavros Sachtouris
            params = dict(self.params)
385 c2b5da2f Stavros Sachtouris
            params.update(async_params)
386 2f749e6e Stavros Sachtouris
            success = kwargs.pop('success', 200)
387 2f749e6e Stavros Sachtouris
            data = kwargs.pop('data', None)
388 c2b5da2f Stavros Sachtouris
            headers.setdefault('X-Auth-Token', self.token)
389 2f749e6e Stavros Sachtouris
            if 'json' in kwargs:
390 de4f08ef Stavros Sachtouris
                data = dumps(kwargs.pop('json'))
391 c2b5da2f Stavros Sachtouris
                headers.setdefault('Content-Type', 'application/json')
392 2f749e6e Stavros Sachtouris
            if data:
393 c2b5da2f Stavros Sachtouris
                headers.setdefault('Content-Length', '%s' % len(data))
394 c2b5da2f Stavros Sachtouris
395 a863029c Stavros Sachtouris
            sendlog.debug('\n\nCMT %s@%s\t[%s]', method, self.base_url, self)
396 c2b5da2f Stavros Sachtouris
            req = RequestManager(
397 c2b5da2f Stavros Sachtouris
                method, self.base_url, path,
398 c2b5da2f Stavros Sachtouris
                data=data, headers=headers, params=params)
399 21871fb2 Stavros Sachtouris
            #  req.log()
400 c2b5da2f Stavros Sachtouris
            r = ResponseManager(req)
401 5fdccdec Stavros Sachtouris
            r.LOG_TOKEN, r.LOG_DATA = self.LOG_TOKEN, self.LOG_DATA
402 6a6175c0 Stavros Sachtouris
        finally:
403 c2b5da2f Stavros Sachtouris
            self.headers = dict()
404 c2b5da2f Stavros Sachtouris
            self.params = dict()
405 0238c167 Stavros Sachtouris
406 0238c167 Stavros Sachtouris
        if success is not None:
407 a037fd61 Stavros Sachtouris
            # Success can either be an int or a collection
408 0238c167 Stavros Sachtouris
            success = (success,) if isinstance(success, int) else success
409 0238c167 Stavros Sachtouris
            if r.status_code not in success:
410 0238c167 Stavros Sachtouris
                self._raise_for_status(r)
411 d726b3d0 Stavros Sachtouris
        return r
412 a1c50326 Giorgos Verigakis
413 6a0b1658 Giorgos Verigakis
    def delete(self, path, **kwargs):
414 6a0b1658 Giorgos Verigakis
        return self.request('delete', path, **kwargs)
415 6a0b1658 Giorgos Verigakis
416 6a0b1658 Giorgos Verigakis
    def get(self, path, **kwargs):
417 6a0b1658 Giorgos Verigakis
        return self.request('get', path, **kwargs)
418 6a0b1658 Giorgos Verigakis
419 6a0b1658 Giorgos Verigakis
    def head(self, path, **kwargs):
420 6a0b1658 Giorgos Verigakis
        return self.request('head', path, **kwargs)
421 6a0b1658 Giorgos Verigakis
422 6a0b1658 Giorgos Verigakis
    def post(self, path, **kwargs):
423 6a0b1658 Giorgos Verigakis
        return self.request('post', path, **kwargs)
424 6a0b1658 Giorgos Verigakis
425 6a0b1658 Giorgos Verigakis
    def put(self, path, **kwargs):
426 6a0b1658 Giorgos Verigakis
        return self.request('put', path, **kwargs)
427 6a0b1658 Giorgos Verigakis
428 4adfa919 Stavros Sachtouris
    def copy(self, path, **kwargs):
429 4adfa919 Stavros Sachtouris
        return self.request('copy', path, **kwargs)
430 4adfa919 Stavros Sachtouris
431 4adfa919 Stavros Sachtouris
    def move(self, path, **kwargs):
432 4adfa919 Stavros Sachtouris
        return self.request('move', path, **kwargs)