Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / __init__.py @ 59dec327

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 a1c50326 Giorgos Verigakis
class ClientError(Exception):
61 a1c50326 Giorgos Verigakis
    def __init__(self, message, status=0, details=''):
62 59dec327 Giorgos Verigakis
        super(ClientError, self).__init__(message, status, details)
63 a1c50326 Giorgos Verigakis
        self.message = message
64 a1c50326 Giorgos Verigakis
        self.status = status
65 a1c50326 Giorgos Verigakis
        self.details = details
66 a1c50326 Giorgos Verigakis
67 a1c50326 Giorgos Verigakis
68 6a0b1658 Giorgos Verigakis
class Client(object):
69 43ca98ee Giorgos Verigakis
    def __init__(self, base_url, token):
70 6a0b1658 Giorgos Verigakis
        self.base_url = base_url
71 6c62a96d Giorgos Verigakis
        self.token = token
72 6c62a96d Giorgos Verigakis
73 43ca98ee Giorgos Verigakis
    def raise_for_status(self, r):        
74 43ca98ee Giorgos Verigakis
        message = "%d %s" % (r.status_code, r.status)
75 43ca98ee Giorgos Verigakis
        details = r.text
76 6a0b1658 Giorgos Verigakis
        raise ClientError(message, r.status_code, details)
77 6a0b1658 Giorgos Verigakis
78 6a0b1658 Giorgos Verigakis
    def request(self, method, path, **kwargs):
79 6a0b1658 Giorgos Verigakis
        raw = kwargs.pop('raw', False)
80 6a0b1658 Giorgos Verigakis
        success = kwargs.pop('success', 200)
81 6c62a96d Giorgos Verigakis
82 6c62a96d Giorgos Verigakis
        data = kwargs.pop('data', None)
83 6c62a96d Giorgos Verigakis
        headers = kwargs.pop('headers', {})
84 6c62a96d Giorgos Verigakis
        headers.setdefault('X-Auth-Token', self.token)
85 6c62a96d Giorgos Verigakis
86 6a0b1658 Giorgos Verigakis
        if 'json' in kwargs:
87 6a0b1658 Giorgos Verigakis
            data = json.dumps(kwargs.pop('json'))
88 6c62a96d Giorgos Verigakis
            headers.setdefault('Content-Type', 'application/json')
89 6c62a96d Giorgos Verigakis
90 6c62a96d Giorgos Verigakis
        if data:
91 6c62a96d Giorgos Verigakis
            headers.setdefault('Content-Length', str(len(data)))
92 6a0b1658 Giorgos Verigakis
93 6a0b1658 Giorgos Verigakis
        url = self.base_url + path
94 be4f79ea Giorgos Verigakis
        kwargs.setdefault('verify', False)  # Disable certificate verification
95 6c62a96d Giorgos Verigakis
        r = requests.request(method, url, headers=headers, data=data, **kwargs)
96 6c62a96d Giorgos Verigakis
97 6a0b1658 Giorgos Verigakis
        req = r.request
98 6a0b1658 Giorgos Verigakis
        sendlog.info('%s %s', req.method, req.url)
99 6a0b1658 Giorgos Verigakis
        for key, val in req.headers.items():
100 6a0b1658 Giorgos Verigakis
            sendlog.info('%s: %s', key, val)
101 6a0b1658 Giorgos Verigakis
        sendlog.info('')
102 6a0b1658 Giorgos Verigakis
        if req.data:
103 6a0b1658 Giorgos Verigakis
            sendlog.info('%s', req.data)
104 6a0b1658 Giorgos Verigakis
        
105 6a0b1658 Giorgos Verigakis
        recvlog.info('%d %s', r.status_code, r.status)
106 6a0b1658 Giorgos Verigakis
        for key, val in r.headers.items():
107 6a0b1658 Giorgos Verigakis
            recvlog.info('%s: %s', key, val)
108 6a0b1658 Giorgos Verigakis
        recvlog.info('')
109 6a0b1658 Giorgos Verigakis
        if not raw and r.text:
110 6a0b1658 Giorgos Verigakis
            recvlog.debug(r.text)
111 6a0b1658 Giorgos Verigakis
        
112 6a0b1658 Giorgos Verigakis
        if success is not None:
113 6a0b1658 Giorgos Verigakis
            # Success can either be an in or a collection
114 6a0b1658 Giorgos Verigakis
            success = (success,) if isinstance(success, int) else success
115 6a0b1658 Giorgos Verigakis
            if r.status_code not in success:
116 6a0b1658 Giorgos Verigakis
                self.raise_for_status(r)
117 6a0b1658 Giorgos Verigakis
118 a1c50326 Giorgos Verigakis
        return r
119 a1c50326 Giorgos Verigakis
120 6a0b1658 Giorgos Verigakis
    def delete(self, path, **kwargs):
121 6a0b1658 Giorgos Verigakis
        return self.request('delete', path, **kwargs)
122 6a0b1658 Giorgos Verigakis
123 6a0b1658 Giorgos Verigakis
    def get(self, path, **kwargs):
124 6a0b1658 Giorgos Verigakis
        return self.request('get', path, **kwargs)
125 6a0b1658 Giorgos Verigakis
126 6a0b1658 Giorgos Verigakis
    def head(self, path, **kwargs):
127 6a0b1658 Giorgos Verigakis
        return self.request('head', path, **kwargs)
128 6a0b1658 Giorgos Verigakis
129 6a0b1658 Giorgos Verigakis
    def post(self, path, **kwargs):
130 6a0b1658 Giorgos Verigakis
        return self.request('post', path, **kwargs)
131 6a0b1658 Giorgos Verigakis
132 6a0b1658 Giorgos Verigakis
    def put(self, path, **kwargs):
133 6a0b1658 Giorgos Verigakis
        return self.request('put', path, **kwargs)
134 6a0b1658 Giorgos Verigakis
135 a1c50326 Giorgos Verigakis
136 6a0b1658 Giorgos Verigakis
from .compute import ComputeClient as compute
137 6a0b1658 Giorgos Verigakis
from .image import ImageClient as image
138 6a0b1658 Giorgos Verigakis
from .storage import StorageClient as storage
139 6a0b1658 Giorgos Verigakis
from .cyclades import CycladesClient as cyclades
140 6a0b1658 Giorgos Verigakis
from .pithos import PithosClient as pithos
141 43ca98ee Giorgos Verigakis
from .astakos import AstakosClient as astakos