Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / __init__.py @ be4f79ea

History | View | Annotate | Download (4.8 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 a1c50326 Giorgos Verigakis
#      copyright notice, this 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 a1c50326 Giorgos Verigakis
#      copyright notice, this 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 6a0b1658 Giorgos Verigakis
37 6a0b1658 Giorgos Verigakis
import requests
38 6a0b1658 Giorgos Verigakis
39 6a0b1658 Giorgos Verigakis
from requests.auth import AuthBase
40 6a0b1658 Giorgos Verigakis
41 6a0b1658 Giorgos Verigakis
42 6a0b1658 Giorgos Verigakis
sendlog = logging.getLogger('clients.send')
43 6a0b1658 Giorgos Verigakis
recvlog = logging.getLogger('clients.recv')
44 6a0b1658 Giorgos Verigakis
45 6a0b1658 Giorgos Verigakis
46 6a0b1658 Giorgos Verigakis
# Add a convenience json property to the responses
47 6a0b1658 Giorgos Verigakis
def _json(self):
48 6a0b1658 Giorgos Verigakis
    try:
49 2bcb595a Giorgos Verigakis
        return json.loads(self.content) if self.content else {}
50 6a0b1658 Giorgos Verigakis
    except ValueError:
51 6a0b1658 Giorgos Verigakis
        raise ClientError("Invalid JSON reply", self.status_code)
52 6a0b1658 Giorgos Verigakis
requests.Response.json = property(_json)
53 6a0b1658 Giorgos Verigakis
54 6a0b1658 Giorgos Verigakis
# Add a convenience status property to the responses
55 6a0b1658 Giorgos Verigakis
def _status(self):
56 6a0b1658 Giorgos Verigakis
    return requests.status_codes._codes[self.status_code][0].upper()
57 6a0b1658 Giorgos Verigakis
requests.Response.status = property(_status)
58 6a0b1658 Giorgos Verigakis
59 6a0b1658 Giorgos Verigakis
60 6a0b1658 Giorgos Verigakis
class XAuthTokenAuth(AuthBase):
61 6a0b1658 Giorgos Verigakis
    def __init__(self, token):
62 6a0b1658 Giorgos Verigakis
        self.token = token
63 6a0b1658 Giorgos Verigakis
    
64 6a0b1658 Giorgos Verigakis
    def __call__(self, r):
65 6a0b1658 Giorgos Verigakis
        r.headers['X-Auth-Token'] = self.token
66 6a0b1658 Giorgos Verigakis
        return r
67 6a0b1658 Giorgos Verigakis
68 6a0b1658 Giorgos Verigakis
69 a1c50326 Giorgos Verigakis
class ClientError(Exception):
70 a1c50326 Giorgos Verigakis
    def __init__(self, message, status=0, details=''):
71 a1c50326 Giorgos Verigakis
        self.message = message
72 a1c50326 Giorgos Verigakis
        self.status = status
73 a1c50326 Giorgos Verigakis
        self.details = details
74 a1c50326 Giorgos Verigakis
75 a1c50326 Giorgos Verigakis
76 6a0b1658 Giorgos Verigakis
class Client(object):
77 43ca98ee Giorgos Verigakis
    def __init__(self, base_url, token):
78 6a0b1658 Giorgos Verigakis
        self.base_url = base_url
79 6a0b1658 Giorgos Verigakis
        self.auth = XAuthTokenAuth(token)
80 6a0b1658 Giorgos Verigakis
    
81 43ca98ee Giorgos Verigakis
    def raise_for_status(self, r):        
82 43ca98ee Giorgos Verigakis
        message = "%d %s" % (r.status_code, r.status)
83 43ca98ee Giorgos Verigakis
        details = r.text
84 6a0b1658 Giorgos Verigakis
        raise ClientError(message, r.status_code, details)
85 6a0b1658 Giorgos Verigakis
86 6a0b1658 Giorgos Verigakis
    def request(self, method, path, **kwargs):
87 6a0b1658 Giorgos Verigakis
        raw = kwargs.pop('raw', False)
88 6a0b1658 Giorgos Verigakis
        success = kwargs.pop('success', 200)
89 6a0b1658 Giorgos Verigakis
        if 'json' in kwargs:
90 6a0b1658 Giorgos Verigakis
            data = json.dumps(kwargs.pop('json'))
91 6a0b1658 Giorgos Verigakis
            kwargs['data'] = data
92 6a0b1658 Giorgos Verigakis
            headers = kwargs.setdefault('headers', {})
93 6a0b1658 Giorgos Verigakis
            headers['content-type'] = 'application/json'
94 6a0b1658 Giorgos Verigakis
95 6a0b1658 Giorgos Verigakis
        url = self.base_url + path
96 6a0b1658 Giorgos Verigakis
        kwargs.setdefault('auth', self.auth)
97 be4f79ea Giorgos Verigakis
        kwargs.setdefault('verify', False)  # Disable certificate verification
98 6a0b1658 Giorgos Verigakis
        r = requests.request(method, url, **kwargs)
99 6a0b1658 Giorgos Verigakis
        
100 6a0b1658 Giorgos Verigakis
        req = r.request
101 6a0b1658 Giorgos Verigakis
        sendlog.info('%s %s', req.method, req.url)
102 6a0b1658 Giorgos Verigakis
        for key, val in req.headers.items():
103 6a0b1658 Giorgos Verigakis
            sendlog.info('%s: %s', key, val)
104 6a0b1658 Giorgos Verigakis
        sendlog.info('')
105 6a0b1658 Giorgos Verigakis
        if req.data:
106 6a0b1658 Giorgos Verigakis
            sendlog.info('%s', req.data)
107 6a0b1658 Giorgos Verigakis
        
108 6a0b1658 Giorgos Verigakis
        recvlog.info('%d %s', r.status_code, r.status)
109 6a0b1658 Giorgos Verigakis
        for key, val in r.headers.items():
110 6a0b1658 Giorgos Verigakis
            recvlog.info('%s: %s', key, val)
111 6a0b1658 Giorgos Verigakis
        recvlog.info('')
112 6a0b1658 Giorgos Verigakis
        if not raw and r.text:
113 6a0b1658 Giorgos Verigakis
            recvlog.debug(r.text)
114 6a0b1658 Giorgos Verigakis
        
115 6a0b1658 Giorgos Verigakis
        if success is not None:
116 6a0b1658 Giorgos Verigakis
            # Success can either be an in or a collection
117 6a0b1658 Giorgos Verigakis
            success = (success,) if isinstance(success, int) else success
118 6a0b1658 Giorgos Verigakis
            if r.status_code not in success:
119 6a0b1658 Giorgos Verigakis
                self.raise_for_status(r)
120 6a0b1658 Giorgos Verigakis
121 a1c50326 Giorgos Verigakis
        return r
122 a1c50326 Giorgos Verigakis
123 6a0b1658 Giorgos Verigakis
    def delete(self, path, **kwargs):
124 6a0b1658 Giorgos Verigakis
        return self.request('delete', path, **kwargs)
125 6a0b1658 Giorgos Verigakis
126 6a0b1658 Giorgos Verigakis
    def get(self, path, **kwargs):
127 6a0b1658 Giorgos Verigakis
        return self.request('get', path, **kwargs)
128 6a0b1658 Giorgos Verigakis
129 6a0b1658 Giorgos Verigakis
    def head(self, path, **kwargs):
130 6a0b1658 Giorgos Verigakis
        return self.request('head', path, **kwargs)
131 6a0b1658 Giorgos Verigakis
132 6a0b1658 Giorgos Verigakis
    def post(self, path, **kwargs):
133 6a0b1658 Giorgos Verigakis
        return self.request('post', path, **kwargs)
134 6a0b1658 Giorgos Verigakis
135 6a0b1658 Giorgos Verigakis
    def put(self, path, **kwargs):
136 6a0b1658 Giorgos Verigakis
        return self.request('put', path, **kwargs)
137 6a0b1658 Giorgos Verigakis
138 a1c50326 Giorgos Verigakis
139 6a0b1658 Giorgos Verigakis
from .compute import ComputeClient as compute
140 6a0b1658 Giorgos Verigakis
from .image import ImageClient as image
141 6a0b1658 Giorgos Verigakis
from .storage import StorageClient as storage
142 6a0b1658 Giorgos Verigakis
from .cyclades import CycladesClient as cyclades
143 6a0b1658 Giorgos Verigakis
from .pithos import PithosClient as pithos
144 43ca98ee Giorgos Verigakis
from .astakos import AstakosClient as astakos