Statistics
| Branch: | Tag: | Revision:

root / pithos / lib / client.py @ a2defd86

History | View | Annotate | Download (15.2 kB)

1 a4c10cbc Sofia Papagiannaki
# Copyright 2011 GRNET S.A. All rights reserved.
2 a4c10cbc Sofia Papagiannaki
# 
3 a4c10cbc Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
4 a4c10cbc Sofia Papagiannaki
# without modification, are permitted provided that the following
5 a4c10cbc Sofia Papagiannaki
# conditions are met:
6 a4c10cbc Sofia Papagiannaki
# 
7 a4c10cbc Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
8 a4c10cbc Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
9 a4c10cbc Sofia Papagiannaki
#      disclaimer.
10 a4c10cbc Sofia Papagiannaki
# 
11 a4c10cbc Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
12 a4c10cbc Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
13 a4c10cbc Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
14 a4c10cbc Sofia Papagiannaki
#      provided with the distribution.
15 a4c10cbc Sofia Papagiannaki
# 
16 a4c10cbc Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 a4c10cbc Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 a4c10cbc Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 a4c10cbc Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 a4c10cbc Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 a4c10cbc Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 a4c10cbc Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 a4c10cbc Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 a4c10cbc Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 a4c10cbc Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 a4c10cbc Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 a4c10cbc Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
28 a4c10cbc Sofia Papagiannaki
# 
29 a4c10cbc Sofia Papagiannaki
# The views and conclusions contained in the software and
30 a4c10cbc Sofia Papagiannaki
# documentation are those of the authors and should not be
31 a4c10cbc Sofia Papagiannaki
# interpreted as representing official policies, either expressed
32 a4c10cbc Sofia Papagiannaki
# or implied, of GRNET S.A.
33 a4c10cbc Sofia Papagiannaki
34 ec1b8d3e Sofia Papagiannaki
from httplib import HTTPConnection, HTTP
35 ec1b8d3e Sofia Papagiannaki
from sys import stdin
36 3f5b02c7 Sofia Papagiannaki
37 3f5b02c7 Sofia Papagiannaki
import json
38 ec1b8d3e Sofia Papagiannaki
import types
39 0ea1dcc4 Sofia Papagiannaki
import socket
40 e3fd7f91 Sofia Papagiannaki
import pithos.api.faults
41 e3fd7f91 Sofia Papagiannaki
42 e3fd7f91 Sofia Papagiannaki
ERROR_CODES = {304:'Not Modified',
43 e3fd7f91 Sofia Papagiannaki
               400:'Bad Request',
44 e3fd7f91 Sofia Papagiannaki
               401:'Unauthorized',
45 e3fd7f91 Sofia Papagiannaki
               404:'Not Found',
46 e3fd7f91 Sofia Papagiannaki
               409:'Conflict',
47 e3fd7f91 Sofia Papagiannaki
               411:'Length Required',
48 e3fd7f91 Sofia Papagiannaki
               412:'Precondition Failed',
49 e3fd7f91 Sofia Papagiannaki
               416:'Range Not Satisfiable',
50 e3fd7f91 Sofia Papagiannaki
               422:'Unprocessable Entity',
51 e3fd7f91 Sofia Papagiannaki
               503:'Service Unavailable'}
52 3f5b02c7 Sofia Papagiannaki
53 3f5b02c7 Sofia Papagiannaki
class Fault(Exception):
54 e3fd7f91 Sofia Papagiannaki
    def __init__(self, data='', status=None):
55 e3fd7f91 Sofia Papagiannaki
        if data == '' and status in ERROR_CODES.keys():
56 e3fd7f91 Sofia Papagiannaki
            data = ERROR_CODES[status]
57 3f5b02c7 Sofia Papagiannaki
        Exception.__init__(self, data)
58 3f5b02c7 Sofia Papagiannaki
        self.data = data
59 e3fd7f91 Sofia Papagiannaki
        self.status = status
60 3f5b02c7 Sofia Papagiannaki
61 3f5b02c7 Sofia Papagiannaki
class Client(object):
62 3f5b02c7 Sofia Papagiannaki
    def __init__(self, host, account, api='v1', verbose=False, debug=False):
63 3f5b02c7 Sofia Papagiannaki
        """`host` can also include a port, e.g '127.0.0.1:8000'."""
64 3f5b02c7 Sofia Papagiannaki
        
65 3f5b02c7 Sofia Papagiannaki
        self.host = host
66 3f5b02c7 Sofia Papagiannaki
        self.account = account
67 3f5b02c7 Sofia Papagiannaki
        self.api = api
68 3f5b02c7 Sofia Papagiannaki
        self.verbose = verbose or debug
69 3f5b02c7 Sofia Papagiannaki
        self.debug = debug
70 f7ab99df Sofia Papagiannaki
    
71 ec1b8d3e Sofia Papagiannaki
    def _chunked_transfer(self, path, method='PUT', f=stdin, headers=None,
72 ec1b8d3e Sofia Papagiannaki
                          blocksize=1024):
73 ec1b8d3e Sofia Papagiannaki
        http = HTTPConnection(self.host)
74 ec1b8d3e Sofia Papagiannaki
        
75 ec1b8d3e Sofia Papagiannaki
        # write header
76 ec1b8d3e Sofia Papagiannaki
        path = '/%s/%s%s' % (self.api, self.account, path)
77 ec1b8d3e Sofia Papagiannaki
        http.putrequest(method, path)
78 ec1b8d3e Sofia Papagiannaki
        http.putheader('Content-Type', 'application/octet-stream')
79 ec1b8d3e Sofia Papagiannaki
        http.putheader('Transfer-Encoding', 'chunked')
80 ec1b8d3e Sofia Papagiannaki
        if headers:
81 ec1b8d3e Sofia Papagiannaki
            for header,value in headers.items():
82 ec1b8d3e Sofia Papagiannaki
                http.putheader(header, value)
83 ec1b8d3e Sofia Papagiannaki
        http.endheaders()
84 ec1b8d3e Sofia Papagiannaki
        
85 ec1b8d3e Sofia Papagiannaki
        # write body
86 ec1b8d3e Sofia Papagiannaki
        data = ''
87 ec1b8d3e Sofia Papagiannaki
        while True:
88 ec1b8d3e Sofia Papagiannaki
            if f.closed:
89 ec1b8d3e Sofia Papagiannaki
                break
90 ec1b8d3e Sofia Papagiannaki
            block = f.read(blocksize)
91 ec1b8d3e Sofia Papagiannaki
            if block == '':
92 ec1b8d3e Sofia Papagiannaki
                break
93 ec1b8d3e Sofia Papagiannaki
            data = '%s\r\n%s\r\n' % (hex(len(block)), block)
94 ec1b8d3e Sofia Papagiannaki
            try:
95 ec1b8d3e Sofia Papagiannaki
                http.send(data)
96 ec1b8d3e Sofia Papagiannaki
            except:
97 ec1b8d3e Sofia Papagiannaki
                #retry
98 ec1b8d3e Sofia Papagiannaki
                http.send(data)
99 ec1b8d3e Sofia Papagiannaki
        data = '0x0\r\n'
100 ec1b8d3e Sofia Papagiannaki
        try:
101 ec1b8d3e Sofia Papagiannaki
            http.send(data)
102 ec1b8d3e Sofia Papagiannaki
        except:
103 ec1b8d3e Sofia Papagiannaki
            #retry
104 ec1b8d3e Sofia Papagiannaki
            http.send(data)
105 ec1b8d3e Sofia Papagiannaki
        
106 ec1b8d3e Sofia Papagiannaki
        # get response
107 ec1b8d3e Sofia Papagiannaki
        resp = http.getresponse()
108 e3fd7f91 Sofia Papagiannaki
        
109 ec1b8d3e Sofia Papagiannaki
        headers = dict(resp.getheaders())
110 ec1b8d3e Sofia Papagiannaki
        
111 ec1b8d3e Sofia Papagiannaki
        if self.verbose:
112 ec1b8d3e Sofia Papagiannaki
            print '%d %s' % (resp.status, resp.reason)
113 ec1b8d3e Sofia Papagiannaki
            for key, val in headers.items():
114 ec1b8d3e Sofia Papagiannaki
                print '%s: %s' % (key.capitalize(), val)
115 ec1b8d3e Sofia Papagiannaki
            print
116 ec1b8d3e Sofia Papagiannaki
        
117 f7ab99df Sofia Papagiannaki
        length = resp.getheader('Content-length', None)
118 6cd1831a Sofia Papagiannaki
        data = resp.read(length)
119 ec1b8d3e Sofia Papagiannaki
        if self.debug:
120 ec1b8d3e Sofia Papagiannaki
            print data
121 ec1b8d3e Sofia Papagiannaki
            print
122 ec1b8d3e Sofia Papagiannaki
        
123 e3fd7f91 Sofia Papagiannaki
        if int(resp.status) in ERROR_CODES.keys():
124 e3fd7f91 Sofia Papagiannaki
            raise Fault(data, int(resp.status))
125 e3fd7f91 Sofia Papagiannaki
        
126 f7ab99df Sofia Papagiannaki
        #print '*',  resp.status, headers, data
127 ec1b8d3e Sofia Papagiannaki
        return resp.status, headers, data
128 f7ab99df Sofia Papagiannaki
    
129 d2d5c360 Sofia Papagiannaki
    def req(self, method, path, body=None, headers=None, format='text',
130 d2d5c360 Sofia Papagiannaki
            params=None):
131 d2d5c360 Sofia Papagiannaki
        full_path = '/%s/%s%s?format=%s' % (self.api, self.account, path,
132 d2d5c360 Sofia Papagiannaki
                                            format)
133 3f5b02c7 Sofia Papagiannaki
        if params:
134 3f5b02c7 Sofia Papagiannaki
            for k,v in params.items():
135 ec1b8d3e Sofia Papagiannaki
                if v:
136 ec1b8d3e Sofia Papagiannaki
                    full_path = '%s&%s=%s' %(full_path, k, v)
137 3f5b02c7 Sofia Papagiannaki
        conn = HTTPConnection(self.host)
138 3f5b02c7 Sofia Papagiannaki
        
139 d2d5c360 Sofia Papagiannaki
        #encode whitespace
140 d2d5c360 Sofia Papagiannaki
        full_path = full_path.replace(' ', '%20')
141 ec1b8d3e Sofia Papagiannaki
        
142 3f5b02c7 Sofia Papagiannaki
        kwargs = {}
143 3f5b02c7 Sofia Papagiannaki
        kwargs['headers'] = headers or {}
144 ec1b8d3e Sofia Papagiannaki
        if not headers or \
145 ec1b8d3e Sofia Papagiannaki
        'Transfer-Encoding' not in headers \
146 ec1b8d3e Sofia Papagiannaki
        or headers['Transfer-Encoding'] != 'chunked':
147 ec1b8d3e Sofia Papagiannaki
            kwargs['headers']['Content-Length'] = len(body) if body else 0
148 3f5b02c7 Sofia Papagiannaki
        if body:
149 3f5b02c7 Sofia Papagiannaki
            kwargs['body'] = body
150 3f5b02c7 Sofia Papagiannaki
            kwargs['headers']['Content-Type'] = 'application/octet-stream'
151 ec1b8d3e Sofia Papagiannaki
        #print '****', method, full_path, kwargs
152 e3fd7f91 Sofia Papagiannaki
        try:
153 e3fd7f91 Sofia Papagiannaki
            conn.request(method, full_path, **kwargs)
154 e3fd7f91 Sofia Papagiannaki
        except socket.error, e:
155 e3fd7f91 Sofia Papagiannaki
            raise Fault(status=503)
156 e3fd7f91 Sofia Papagiannaki
            
157 3f5b02c7 Sofia Papagiannaki
        resp = conn.getresponse()
158 3f5b02c7 Sofia Papagiannaki
        headers = dict(resp.getheaders())
159 3f5b02c7 Sofia Papagiannaki
        
160 3f5b02c7 Sofia Papagiannaki
        if self.verbose:
161 3f5b02c7 Sofia Papagiannaki
            print '%d %s' % (resp.status, resp.reason)
162 3f5b02c7 Sofia Papagiannaki
            for key, val in headers.items():
163 3f5b02c7 Sofia Papagiannaki
                print '%s: %s' % (key.capitalize(), val)
164 3f5b02c7 Sofia Papagiannaki
            print
165 3f5b02c7 Sofia Papagiannaki
        
166 f7ab99df Sofia Papagiannaki
        length = resp.getheader('Content-length', None)
167 6cd1831a Sofia Papagiannaki
        data = resp.read(length)
168 3f5b02c7 Sofia Papagiannaki
        if self.debug:
169 3f5b02c7 Sofia Papagiannaki
            print data
170 3f5b02c7 Sofia Papagiannaki
            print
171 3f5b02c7 Sofia Papagiannaki
        
172 e3fd7f91 Sofia Papagiannaki
        if int(resp.status) in ERROR_CODES.keys():
173 e3fd7f91 Sofia Papagiannaki
            raise Fault(data, int(resp.status))
174 e3fd7f91 Sofia Papagiannaki
        
175 e3fd7f91 Sofia Papagiannaki
        #print '*',  resp.status, headers, data
176 3f5b02c7 Sofia Papagiannaki
        return resp.status, headers, data
177 f7ab99df Sofia Papagiannaki
    
178 3f5b02c7 Sofia Papagiannaki
    def delete(self, path, format='text'):
179 3f5b02c7 Sofia Papagiannaki
        return self.req('DELETE', path, format=format)
180 f7ab99df Sofia Papagiannaki
    
181 3f5b02c7 Sofia Papagiannaki
    def get(self, path, format='text', headers=None, params=None):
182 3f5b02c7 Sofia Papagiannaki
        return self.req('GET', path, headers=headers, format=format,
183 ec1b8d3e Sofia Papagiannaki
                        params=params)
184 f7ab99df Sofia Papagiannaki
    
185 d2d5c360 Sofia Papagiannaki
    def head(self, path, format='text', params=None):
186 d2d5c360 Sofia Papagiannaki
        return self.req('HEAD', path, format=format, params=params)
187 f7ab99df Sofia Papagiannaki
    
188 3f5b02c7 Sofia Papagiannaki
    def post(self, path, body=None, format='text', headers=None):
189 3f5b02c7 Sofia Papagiannaki
        return self.req('POST', path, body, headers=headers, format=format)
190 f7ab99df Sofia Papagiannaki
    
191 3f5b02c7 Sofia Papagiannaki
    def put(self, path, body=None, format='text', headers=None):
192 3f5b02c7 Sofia Papagiannaki
        return self.req('PUT', path, body, headers=headers, format=format)
193 f7ab99df Sofia Papagiannaki
    
194 3f5b02c7 Sofia Papagiannaki
    def _list(self, path, detail=False, params=None, headers=None):
195 3f5b02c7 Sofia Papagiannaki
        format = 'json' if detail else 'text'
196 3f5b02c7 Sofia Papagiannaki
        status, headers, data = self.get(path, format=format, headers=headers,
197 3f5b02c7 Sofia Papagiannaki
                                         params=params)
198 ec1b8d3e Sofia Papagiannaki
        if detail:
199 ec1b8d3e Sofia Papagiannaki
            data = json.loads(data)
200 ec1b8d3e Sofia Papagiannaki
        else:
201 b41a95a0 Sofia Papagiannaki
            data = data.strip().split('\n')
202 3f5b02c7 Sofia Papagiannaki
        return data
203 f7ab99df Sofia Papagiannaki
    
204 d2d5c360 Sofia Papagiannaki
    def _get_metadata(self, path, prefix=None, params=None):
205 d2d5c360 Sofia Papagiannaki
        status, headers, data = self.head(path, params=params)
206 f7ab99df Sofia Papagiannaki
        prefixlen = len(prefix) if prefix else 0
207 3f5b02c7 Sofia Papagiannaki
        meta = {}
208 3f5b02c7 Sofia Papagiannaki
        for key, val in headers.items():
209 0ea1dcc4 Sofia Papagiannaki
            if prefix and not key.startswith(prefix):
210 0ea1dcc4 Sofia Papagiannaki
                continue
211 0ea1dcc4 Sofia Papagiannaki
            elif prefix and key.startswith(prefix):
212 3f5b02c7 Sofia Papagiannaki
                key = key[prefixlen:]
213 0ea1dcc4 Sofia Papagiannaki
            meta[key] = val
214 3f5b02c7 Sofia Papagiannaki
        return meta
215 f7ab99df Sofia Papagiannaki
    
216 f7ab99df Sofia Papagiannaki
    def _update_metadata(self, path, entity, **meta):
217 f7ab99df Sofia Papagiannaki
        """
218 f7ab99df Sofia Papagiannaki
         adds new and updates the values of previously set metadata
219 f7ab99df Sofia Papagiannaki
        """
220 961f2fbe Sofia Papagiannaki
        prefix = 'x-%s-meta-' % entity
221 961f2fbe Sofia Papagiannaki
        prev_meta = self._get_metadata(path, prefix)
222 f7ab99df Sofia Papagiannaki
        prev_meta.update(meta)
223 f7ab99df Sofia Papagiannaki
        headers = {}
224 f7ab99df Sofia Papagiannaki
        for key, val in prev_meta.items():
225 961f2fbe Sofia Papagiannaki
            key = '%s%s' % (prefix, key)
226 961f2fbe Sofia Papagiannaki
            key = '-'.join(elem.capitalize() for elem in key.split('-'))
227 961f2fbe Sofia Papagiannaki
            headers[key] = val
228 f7ab99df Sofia Papagiannaki
        self.post(path, headers=headers)
229 f7ab99df Sofia Papagiannaki
    
230 f7ab99df Sofia Papagiannaki
    def _delete_metadata(self, path, entity, meta=[]):
231 f7ab99df Sofia Papagiannaki
        """
232 f7ab99df Sofia Papagiannaki
        delete previously set metadata
233 f7ab99df Sofia Papagiannaki
        """
234 961f2fbe Sofia Papagiannaki
        prefix = 'x-%s-meta-' % entity
235 961f2fbe Sofia Papagiannaki
        prev_meta = self._get_metadata(path, prefix)
236 f7ab99df Sofia Papagiannaki
        headers = {}
237 f7ab99df Sofia Papagiannaki
        for key, val in prev_meta.items():
238 961f2fbe Sofia Papagiannaki
            if key in meta:
239 f7ab99df Sofia Papagiannaki
                continue
240 961f2fbe Sofia Papagiannaki
            key = '%s%s' % (prefix, key)
241 961f2fbe Sofia Papagiannaki
            key = '-'.join(elem.capitalize() for elem in key.split('-'))
242 961f2fbe Sofia Papagiannaki
            headers[key] = val
243 3f5b02c7 Sofia Papagiannaki
        self.post(path, headers=headers)
244 f7ab99df Sofia Papagiannaki
    
245 3f5b02c7 Sofia Papagiannaki
    # Storage Account Services
246 f7ab99df Sofia Papagiannaki
    
247 ec1b8d3e Sofia Papagiannaki
    def list_containers(self, detail=False, params=None, headers=None):
248 3f5b02c7 Sofia Papagiannaki
        return self._list('', detail, params, headers)
249 f7ab99df Sofia Papagiannaki
    
250 d2d5c360 Sofia Papagiannaki
    def account_metadata(self, restricted=False, until=None):
251 f7ab99df Sofia Papagiannaki
        prefix = 'x-account-meta-' if restricted else None
252 f7ab99df Sofia Papagiannaki
        params = {'until':until} if until else None
253 d2d5c360 Sofia Papagiannaki
        return self._get_metadata('', prefix, params=params)
254 f7ab99df Sofia Papagiannaki
    
255 3f5b02c7 Sofia Papagiannaki
    def update_account_metadata(self, **meta):
256 f7ab99df Sofia Papagiannaki
        self._update_metadata('', 'account', **meta)
257 f7ab99df Sofia Papagiannaki
        
258 f7ab99df Sofia Papagiannaki
    def delete_account_metadata(self, meta=[]):
259 f7ab99df Sofia Papagiannaki
        self._delete_metadata('', 'account', meta)
260 f7ab99df Sofia Papagiannaki
    
261 d3fd269f Sofia Papagiannaki
    def set_account_groups(self, groups):
262 d3fd269f Sofia Papagiannaki
        headers = {}
263 d3fd269f Sofia Papagiannaki
        for key, val in groups.items():
264 d3fd269f Sofia Papagiannaki
            headers['X-Account-Group-%s' % key.capitalize()] = val
265 d3fd269f Sofia Papagiannaki
        self.post('', headers=headers)
266 d3fd269f Sofia Papagiannaki
    
267 3f5b02c7 Sofia Papagiannaki
    # Storage Container Services
268 f7ab99df Sofia Papagiannaki
    
269 a4c10cbc Sofia Papagiannaki
    def _filter(self, l, d):
270 a4c10cbc Sofia Papagiannaki
        """
271 a4c10cbc Sofia Papagiannaki
        filter out from l elements having the metadata values provided
272 a4c10cbc Sofia Papagiannaki
        """
273 a4c10cbc Sofia Papagiannaki
        ll = l
274 a4c10cbc Sofia Papagiannaki
        for elem in l:
275 a4c10cbc Sofia Papagiannaki
            if type(elem) == types.DictionaryType:
276 a4c10cbc Sofia Papagiannaki
                for key in d.keys():
277 a4c10cbc Sofia Papagiannaki
                    k = 'x_object_meta_%s' % key
278 a4c10cbc Sofia Papagiannaki
                    if k in elem.keys() and elem[k] == d[key]:
279 a4c10cbc Sofia Papagiannaki
                        ll.remove(elem)
280 a4c10cbc Sofia Papagiannaki
                        break
281 a4c10cbc Sofia Papagiannaki
        return ll
282 a4c10cbc Sofia Papagiannaki
    
283 a4c10cbc Sofia Papagiannaki
    def _filter_trashed(self, l):
284 a4c10cbc Sofia Papagiannaki
        return self._filter(l, {'trash':'true'})
285 a4c10cbc Sofia Papagiannaki
    
286 a4c10cbc Sofia Papagiannaki
    def list_objects(self, container, detail=False, params=None, headers=None,
287 a4c10cbc Sofia Papagiannaki
                     include_trashed=False):
288 a4c10cbc Sofia Papagiannaki
        l = self._list('/' + container, detail, params, headers)
289 a4c10cbc Sofia Papagiannaki
        if not include_trashed:
290 a4c10cbc Sofia Papagiannaki
            l = self._filter_trashed(l)
291 a4c10cbc Sofia Papagiannaki
        return l
292 f7ab99df Sofia Papagiannaki
    
293 ec1b8d3e Sofia Papagiannaki
    def create_container(self, container, headers=None):
294 ec1b8d3e Sofia Papagiannaki
        status, header, data = self.put('/' + container, headers=headers)
295 3f5b02c7 Sofia Papagiannaki
        if status == 202:
296 3f5b02c7 Sofia Papagiannaki
            return False
297 3f5b02c7 Sofia Papagiannaki
        elif status != 201:
298 e3fd7f91 Sofia Papagiannaki
            raise Fault(data, int(status))
299 3f5b02c7 Sofia Papagiannaki
        return True
300 f7ab99df Sofia Papagiannaki
    
301 3f5b02c7 Sofia Papagiannaki
    def delete_container(self, container):
302 3f5b02c7 Sofia Papagiannaki
        self.delete('/' + container)
303 f7ab99df Sofia Papagiannaki
    
304 d2d5c360 Sofia Papagiannaki
    def retrieve_container_metadata(self, container, restricted=False,
305 d2d5c360 Sofia Papagiannaki
                                    until=None):
306 f7ab99df Sofia Papagiannaki
        prefix = 'x-container-meta-' if restricted else None
307 f7ab99df Sofia Papagiannaki
        params = {'until':until} if until else None
308 d2d5c360 Sofia Papagiannaki
        return self._get_metadata('/%s' % container, prefix, params=params)
309 f7ab99df Sofia Papagiannaki
    
310 3f5b02c7 Sofia Papagiannaki
    def update_container_metadata(self, container, **meta):
311 f7ab99df Sofia Papagiannaki
        self._update_metadata('/' + container, 'container', **meta)
312 f7ab99df Sofia Papagiannaki
        
313 f7ab99df Sofia Papagiannaki
    def delete_container_metadata(self, container, meta=[]):
314 f7ab99df Sofia Papagiannaki
        path = '/%s' % (container)
315 f7ab99df Sofia Papagiannaki
        self._delete_metadata(path, 'container', meta)
316 f7ab99df Sofia Papagiannaki
    
317 3f5b02c7 Sofia Papagiannaki
    # Storage Object Services
318 f7ab99df Sofia Papagiannaki
    
319 8fe01d72 Sofia Papagiannaki
    def retrieve_object(self, container, object, detail=False, headers=None,
320 8fe01d72 Sofia Papagiannaki
                        version=None):
321 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
322 ec1b8d3e Sofia Papagiannaki
        format = 'json' if detail else 'text'
323 f7ab99df Sofia Papagiannaki
        params = {'version':version} if version else None 
324 8fe01d72 Sofia Papagiannaki
        status, headers, data = self.get(path, format, headers, params)
325 3f5b02c7 Sofia Papagiannaki
        return data
326 f7ab99df Sofia Papagiannaki
    
327 f7ab99df Sofia Papagiannaki
    def create_directory_marker(self, container, object):
328 f7ab99df Sofia Papagiannaki
        if not object:
329 f7ab99df Sofia Papagiannaki
            raise Fault('Directory markers have to be nested in a container')
330 f7ab99df Sofia Papagiannaki
        h = {'Content-Type':'application/directory'}
331 f7ab99df Sofia Papagiannaki
        self.create_object(container, object, f=None, headers=h)
332 f7ab99df Sofia Papagiannaki
    
333 ec1b8d3e Sofia Papagiannaki
    def create_object(self, container, object, f=stdin, chunked=False,
334 ec1b8d3e Sofia Papagiannaki
                      blocksize=1024, headers=None):
335 d2d5c360 Sofia Papagiannaki
        """
336 d2d5c360 Sofia Papagiannaki
        creates an object
337 d2d5c360 Sofia Papagiannaki
        if f is None then creates a zero length object
338 d2d5c360 Sofia Papagiannaki
        if f is stdin or chunked is set then performs chunked transfer 
339 d2d5c360 Sofia Papagiannaki
        """
340 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
341 ec1b8d3e Sofia Papagiannaki
        if not chunked and f != stdin:
342 f7ab99df Sofia Papagiannaki
            data = f.read() if f else None
343 e3fd7f91 Sofia Papagiannaki
            return self.put(path, data, headers=headers)
344 ec1b8d3e Sofia Papagiannaki
        else:
345 e3fd7f91 Sofia Papagiannaki
            return self._chunked_transfer(path, 'PUT', f, headers=headers,
346 ec1b8d3e Sofia Papagiannaki
                                   blocksize=1024)
347 f7ab99df Sofia Papagiannaki
    
348 ec1b8d3e Sofia Papagiannaki
    def update_object(self, container, object, f=stdin, chunked=False,
349 ec1b8d3e Sofia Papagiannaki
                      blocksize=1024, headers=None):
350 ec1b8d3e Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
351 ec1b8d3e Sofia Papagiannaki
        if not chunked and f != stdin:
352 a2defd86 Sofia Papagiannaki
            data = f.read() if f else None
353 ec1b8d3e Sofia Papagiannaki
            self.post(path, data, headers=headers)
354 ec1b8d3e Sofia Papagiannaki
        else:
355 ec1b8d3e Sofia Papagiannaki
            self._chunked_transfer(path, 'POST', f, headers=headers,
356 ec1b8d3e Sofia Papagiannaki
                                   blocksize=1024)
357 f7ab99df Sofia Papagiannaki
    
358 ec1b8d3e Sofia Papagiannaki
    def _change_obj_location(self, src_container, src_object, dst_container,
359 ad71a0ce Sofia Papagiannaki
                             dst_object, remove=False, headers=None):
360 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (dst_container, dst_object)
361 ad71a0ce Sofia Papagiannaki
        if not headers:
362 ad71a0ce Sofia Papagiannaki
            headers = {}
363 ec1b8d3e Sofia Papagiannaki
        if remove:
364 ec1b8d3e Sofia Papagiannaki
            headers['X-Move-From'] = '/%s/%s' % (src_container, src_object)
365 ec1b8d3e Sofia Papagiannaki
        else:
366 ec1b8d3e Sofia Papagiannaki
            headers['X-Copy-From'] = '/%s/%s' % (src_container, src_object)
367 3f5b02c7 Sofia Papagiannaki
        headers['Content-Length'] = 0
368 3f5b02c7 Sofia Papagiannaki
        self.put(path, headers=headers)
369 f7ab99df Sofia Papagiannaki
    
370 ec1b8d3e Sofia Papagiannaki
    def copy_object(self, src_container, src_object, dst_container,
371 ad71a0ce Sofia Papagiannaki
                             dst_object, headers=None):
372 ec1b8d3e Sofia Papagiannaki
        self._change_obj_location(src_container, src_object,
373 7e999dec Sofia Papagiannaki
                                   dst_container, dst_object,
374 7e999dec Sofia Papagiannaki
                                   headers=headers)
375 f7ab99df Sofia Papagiannaki
    
376 ec1b8d3e Sofia Papagiannaki
    def move_object(self, src_container, src_object, dst_container,
377 ad71a0ce Sofia Papagiannaki
                             dst_object, headers=None):
378 ec1b8d3e Sofia Papagiannaki
        self._change_obj_location(src_container, src_object,
379 ad71a0ce Sofia Papagiannaki
                                   dst_container, dst_object, True, headers)
380 f7ab99df Sofia Papagiannaki
    
381 3f5b02c7 Sofia Papagiannaki
    def delete_object(self, container, object):
382 3f5b02c7 Sofia Papagiannaki
        self.delete('/%s/%s' % (container, object))
383 f7ab99df Sofia Papagiannaki
    
384 8fe01d72 Sofia Papagiannaki
    def retrieve_object_metadata(self, container, object, restricted=False,
385 8fe01d72 Sofia Papagiannaki
                                 version=None):
386 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
387 f7ab99df Sofia Papagiannaki
        prefix = 'x-object-meta-' if restricted else None
388 f7ab99df Sofia Papagiannaki
        params = {'version':version} if version else None
389 8fe01d72 Sofia Papagiannaki
        return self._get_metadata(path, prefix, params=params)
390 f7ab99df Sofia Papagiannaki
    
391 3f5b02c7 Sofia Papagiannaki
    def update_object_metadata(self, container, object, **meta):
392 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
393 f7ab99df Sofia Papagiannaki
        self._update_metadata(path, 'object', **meta)
394 f7ab99df Sofia Papagiannaki
    
395 f7ab99df Sofia Papagiannaki
    def delete_object_metadata(self, container, object, meta=[]):
396 f7ab99df Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
397 f7ab99df Sofia Papagiannaki
        self._delete_metadata(path, 'object', meta)
398 f7ab99df Sofia Papagiannaki
    
399 f7ab99df Sofia Papagiannaki
    def trash_object(self, container, object):
400 f7ab99df Sofia Papagiannaki
        """
401 f7ab99df Sofia Papagiannaki
        trashes an object
402 f7ab99df Sofia Papagiannaki
        actually resets all object metadata with trash = true 
403 f7ab99df Sofia Papagiannaki
        """
404 f7ab99df Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
405 f7ab99df Sofia Papagiannaki
        meta = {'trash':'true'}
406 f7ab99df Sofia Papagiannaki
        self._update_metadata(path, 'object', **meta)
407 f7ab99df Sofia Papagiannaki
    
408 f7ab99df Sofia Papagiannaki
    def restore_object(self, container, object):
409 f7ab99df Sofia Papagiannaki
        """
410 f7ab99df Sofia Papagiannaki
        restores a trashed object
411 961f2fbe Sofia Papagiannaki
        actualy removes trash object metadata info
412 f7ab99df Sofia Papagiannaki
        """
413 f7ab99df Sofia Papagiannaki
        self.delete_object_metadata(container, object, ['trash'])