Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / __init__.py @ b335416e

History | View | Annotate | Download (6.1 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 6a0b1658 Giorgos Verigakis
import json
35 6a0b1658 Giorgos Verigakis
import logging
36 c270fe96 Stavros Sachtouris
from kamaki.clients.connection import HTTPConnectionError
37 c270fe96 Stavros Sachtouris
from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
38 6a0b1658 Giorgos Verigakis
39 6a0b1658 Giorgos Verigakis
sendlog = logging.getLogger('clients.send')
40 6a0b1658 Giorgos Verigakis
recvlog = logging.getLogger('clients.recv')
41 6a0b1658 Giorgos Verigakis
42 a1c50326 Giorgos Verigakis
class ClientError(Exception):
43 a1c50326 Giorgos Verigakis
    def __init__(self, message, status=0, details=''):
44 59dec327 Giorgos Verigakis
        super(ClientError, self).__init__(message, status, details)
45 a1c50326 Giorgos Verigakis
        self.message = message
46 a1c50326 Giorgos Verigakis
        self.status = status
47 a1c50326 Giorgos Verigakis
        self.details = details
48 a1c50326 Giorgos Verigakis
49 6a0b1658 Giorgos Verigakis
class Client(object):
50 a2e8e549 Stavros Sachtouris
51 5b263ba2 Stavros Sachtouris
    def __init__(self, base_url, token, http_client=KamakiHTTPConnection()):
52 6a0b1658 Giorgos Verigakis
        self.base_url = base_url
53 6c62a96d Giorgos Verigakis
        self.token = token
54 e742badc Stavros Sachtouris
        self.headers = {}
55 16ce7b91 Stavros Sachtouris
        self.DATE_FORMATS = ["%a %b %d %H:%M:%S %Y",
56 16ce7b91 Stavros Sachtouris
            "%A, %d-%b-%y %H:%M:%S GMT",
57 16ce7b91 Stavros Sachtouris
            "%a, %d %b %Y %H:%M:%S GMT"]
58 a2e8e549 Stavros Sachtouris
        self.http_client = http_client
59 6c62a96d Giorgos Verigakis
60 6ad245d5 Stavros Sachtouris
    def _raise_for_status(self, r):
61 adb1dde9 Stavros Sachtouris
        message = "%s" % r.status
62 d804de82 Stavros Sachtouris
        try:
63 d804de82 Stavros Sachtouris
            details = r.text
64 d804de82 Stavros Sachtouris
        except:
65 d804de82 Stavros Sachtouris
            details = ''
66 adb1dde9 Stavros Sachtouris
        raise ClientError(message=message, status=r.status_code, details=details)
67 6a0b1658 Giorgos Verigakis
68 4adfa919 Stavros Sachtouris
    def set_header(self, name, value, iff=True):
69 4adfa919 Stavros Sachtouris
        """Set a header 'name':'value' provided value is not None and iff is True"""
70 4adfa919 Stavros Sachtouris
        if value is not None and iff:
71 2f749e6e Stavros Sachtouris
            self.http_client.set_header(name, value)
72 2f749e6e Stavros Sachtouris
73 2f749e6e Stavros Sachtouris
    def set_param(self, name, value=None, iff=True):
74 2f749e6e Stavros Sachtouris
        if iff:
75 2f749e6e Stavros Sachtouris
            self.http_client.set_param(name, value)
76 2f749e6e Stavros Sachtouris
77 2f749e6e Stavros Sachtouris
    def set_default_header(self, name, value):
78 2f749e6e Stavros Sachtouris
        self.http_client.headers.setdefault(name, value)
79 e742badc Stavros Sachtouris
80 6ce9fc72 Stavros Sachtouris
    def request(self,
81 6ce9fc72 Stavros Sachtouris
        method,
82 6ce9fc72 Stavros Sachtouris
        path,
83 6ce9fc72 Stavros Sachtouris
        async_headers={},
84 6ce9fc72 Stavros Sachtouris
        async_params={},
85 6ce9fc72 Stavros Sachtouris
        **kwargs):
86 9a7efb0d Stavros Sachtouris
        """In threaded/asynchronous requests, headers and params are not safe
87 9a7efb0d Stavros Sachtouris
        Therefore, the standard self.set_header/param system can be used only for 
88 9a7efb0d Stavros Sachtouris
        headers and params that are common for all requests. All other params and
89 9a7efb0d Stavros Sachtouris
        headers should passes as
90 9a7efb0d Stavros Sachtouris
        @param async_headers
91 9a7efb0d Stavros Sachtouris
        @async_params
92 9a7efb0d Stavros Sachtouris
        E.g. in most queries the 'X-Auth-Token' header might be the same for all, but the
93 9a7efb0d Stavros Sachtouris
        'Range' header might be different from request to request.
94 9a7efb0d Stavros Sachtouris
        """
95 1785ad41 Stavros Sachtouris
96 d726b3d0 Stavros Sachtouris
        try:
97 2f749e6e Stavros Sachtouris
            success = kwargs.pop('success', 200)
98 2f749e6e Stavros Sachtouris
99 2f749e6e Stavros Sachtouris
            data = kwargs.pop('data', None)
100 2f749e6e Stavros Sachtouris
            self.set_default_header('X-Auth-Token', self.token)
101 2f749e6e Stavros Sachtouris
102 2f749e6e Stavros Sachtouris
            if 'json' in kwargs:
103 2f749e6e Stavros Sachtouris
                data = json.dumps(kwargs.pop('json'))
104 2f749e6e Stavros Sachtouris
                self.set_default_header('Content-Type', 'application/json')
105 2f749e6e Stavros Sachtouris
            if data:
106 2f749e6e Stavros Sachtouris
                self.set_default_header('Content-Length', unicode(len(data)))
107 2f749e6e Stavros Sachtouris
108 2f749e6e Stavros Sachtouris
            self.http_client.url = self.base_url + path
109 9a7efb0d Stavros Sachtouris
            r = self.http_client.perform_request(method, data, async_headers, async_params)
110 2f749e6e Stavros Sachtouris
111 2f749e6e Stavros Sachtouris
            req = self.http_client
112 5b263ba2 Stavros Sachtouris
            sendlog.info('%s %s', method, req.url)
113 1785ad41 Stavros Sachtouris
            headers = dict(req.headers)
114 1785ad41 Stavros Sachtouris
            headers.update(async_headers)
115 1785ad41 Stavros Sachtouris
116 1785ad41 Stavros Sachtouris
            for key, val in headers.items():
117 1785ad41 Stavros Sachtouris
                sendlog.info('\t%s: %s', key, val)
118 2f749e6e Stavros Sachtouris
            sendlog.info('')
119 2f749e6e Stavros Sachtouris
            if data:
120 2f749e6e Stavros Sachtouris
                sendlog.info('%s', data)
121 2f749e6e Stavros Sachtouris
122 2f749e6e Stavros Sachtouris
            recvlog.info('%d %s', r.status_code, r.status)
123 2f749e6e Stavros Sachtouris
            for key, val in r.headers.items():
124 2f749e6e Stavros Sachtouris
                recvlog.info('%s: %s', key, val)
125 9a7efb0d Stavros Sachtouris
            #if r.content:
126 9a7efb0d Stavros Sachtouris
            #    recvlog.debug(r.content)
127 2f749e6e Stavros Sachtouris
128 2f749e6e Stavros Sachtouris
            if success is not None:
129 2f749e6e Stavros Sachtouris
                # Success can either be an in or a collection
130 2f749e6e Stavros Sachtouris
                success = (success,) if isinstance(success, int) else success
131 2f749e6e Stavros Sachtouris
                if r.status_code not in success:
132 a34888b4 Stavros Sachtouris
                    r.release()
133 6ad245d5 Stavros Sachtouris
                    self._raise_for_status(r)
134 58821ef5 Stavros Sachtouris
        except Exception as err:
135 2f749e6e Stavros Sachtouris
            self.http_client.reset_headers()
136 2f749e6e Stavros Sachtouris
            self.http_client.reset_params()
137 b9d07587 Stavros Sachtouris
            errmsg = getattr(err, 'message', unicode(err))
138 b9d07587 Stavros Sachtouris
            errdetails = getattr(err, 'details', '')+' (%s)'%type(err)
139 b9d07587 Stavros Sachtouris
            errstatus = getattr(err, 'status', 0)
140 b9d07587 Stavros Sachtouris
            raise ClientError(message=errmsg,status=errstatus,details=errdetails)
141 a52d2256 Stavros Sachtouris
142 a52d2256 Stavros Sachtouris
        self.http_client.reset_headers()
143 a52d2256 Stavros Sachtouris
        self.http_client.reset_params()
144 d726b3d0 Stavros Sachtouris
        return r
145 a1c50326 Giorgos Verigakis
146 6a0b1658 Giorgos Verigakis
    def delete(self, path, **kwargs):
147 6a0b1658 Giorgos Verigakis
        return self.request('delete', path, **kwargs)
148 6a0b1658 Giorgos Verigakis
149 6a0b1658 Giorgos Verigakis
    def get(self, path, **kwargs):
150 6a0b1658 Giorgos Verigakis
        return self.request('get', path, **kwargs)
151 6a0b1658 Giorgos Verigakis
152 6a0b1658 Giorgos Verigakis
    def head(self, path, **kwargs):
153 6a0b1658 Giorgos Verigakis
        return self.request('head', path, **kwargs)
154 6a0b1658 Giorgos Verigakis
155 6a0b1658 Giorgos Verigakis
    def post(self, path, **kwargs):
156 6a0b1658 Giorgos Verigakis
        return self.request('post', path, **kwargs)
157 6a0b1658 Giorgos Verigakis
158 6a0b1658 Giorgos Verigakis
    def put(self, path, **kwargs):
159 6a0b1658 Giorgos Verigakis
        return self.request('put', path, **kwargs)
160 6a0b1658 Giorgos Verigakis
161 4adfa919 Stavros Sachtouris
    def copy(self, path, **kwargs):
162 4adfa919 Stavros Sachtouris
        return self.request('copy', path, **kwargs)
163 4adfa919 Stavros Sachtouris
164 4adfa919 Stavros Sachtouris
    def move(self, path, **kwargs):
165 4adfa919 Stavros Sachtouris
        return self.request('move', path, **kwargs)