Statistics
| Branch: | Tag: | Revision:

root / pithos / lib / client.py @ d6c6f6c7

History | View | Annotate | Download (33.8 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 f0eacc2c Sofia Papagiannaki
from xml.dom import minidom
37 3f5b02c7 Sofia Papagiannaki
38 3f5b02c7 Sofia Papagiannaki
import json
39 ec1b8d3e Sofia Papagiannaki
import types
40 0ea1dcc4 Sofia Papagiannaki
import socket
41 ae75584f Sofia Papagiannaki
import urllib
42 e3fd7f91 Sofia Papagiannaki
import pithos.api.faults
43 e3fd7f91 Sofia Papagiannaki
44 e3fd7f91 Sofia Papagiannaki
ERROR_CODES = {304:'Not Modified',
45 e3fd7f91 Sofia Papagiannaki
               400:'Bad Request',
46 e3fd7f91 Sofia Papagiannaki
               401:'Unauthorized',
47 e3fd7f91 Sofia Papagiannaki
               404:'Not Found',
48 e3fd7f91 Sofia Papagiannaki
               409:'Conflict',
49 e3fd7f91 Sofia Papagiannaki
               411:'Length Required',
50 e3fd7f91 Sofia Papagiannaki
               412:'Precondition Failed',
51 e3fd7f91 Sofia Papagiannaki
               416:'Range Not Satisfiable',
52 e3fd7f91 Sofia Papagiannaki
               422:'Unprocessable Entity',
53 e3fd7f91 Sofia Papagiannaki
               503:'Service Unavailable'}
54 3f5b02c7 Sofia Papagiannaki
55 3f5b02c7 Sofia Papagiannaki
class Fault(Exception):
56 e3fd7f91 Sofia Papagiannaki
    def __init__(self, data='', status=None):
57 e3fd7f91 Sofia Papagiannaki
        if data == '' and status in ERROR_CODES.keys():
58 e3fd7f91 Sofia Papagiannaki
            data = ERROR_CODES[status]
59 3f5b02c7 Sofia Papagiannaki
        Exception.__init__(self, data)
60 3f5b02c7 Sofia Papagiannaki
        self.data = data
61 e3fd7f91 Sofia Papagiannaki
        self.status = status
62 3f5b02c7 Sofia Papagiannaki
63 3f5b02c7 Sofia Papagiannaki
class Client(object):
64 bcb7c5a8 Sofia Papagiannaki
    def __init__(self, host, token, account, api='v1', verbose=False, debug=False):
65 3f5b02c7 Sofia Papagiannaki
        """`host` can also include a port, e.g '127.0.0.1:8000'."""
66 3f5b02c7 Sofia Papagiannaki
        
67 3f5b02c7 Sofia Papagiannaki
        self.host = host
68 3f5b02c7 Sofia Papagiannaki
        self.account = account
69 3f5b02c7 Sofia Papagiannaki
        self.api = api
70 3f5b02c7 Sofia Papagiannaki
        self.verbose = verbose or debug
71 3f5b02c7 Sofia Papagiannaki
        self.debug = debug
72 bcb7c5a8 Sofia Papagiannaki
        self.token = token
73 f7ab99df Sofia Papagiannaki
    
74 25c3841c Sofia Papagiannaki
    def _req(self, method, path, body=None, headers={}, format='text',
75 ae75584f Sofia Papagiannaki
             params={}, top_level_req=False):
76 ae75584f Sofia Papagiannaki
        path = urllib.quote(path)
77 ae75584f Sofia Papagiannaki
        account = '' if top_level_req else self.account
78 ae75584f Sofia Papagiannaki
        full_path = '/%s/%s%s?format=%s' % (self.api, account, path, format)
79 ae75584f Sofia Papagiannaki
        
80 25c3841c Sofia Papagiannaki
        for k,v in params.items():
81 25c3841c Sofia Papagiannaki
            if v:
82 25c3841c Sofia Papagiannaki
                full_path = '%s&%s=%s' %(full_path, k, v)
83 25c3841c Sofia Papagiannaki
            else:
84 25c3841c Sofia Papagiannaki
                full_path = '%s&%s' %(full_path, k)
85 3f5b02c7 Sofia Papagiannaki
        conn = HTTPConnection(self.host)
86 3f5b02c7 Sofia Papagiannaki
        
87 d2d5c360 Sofia Papagiannaki
        #encode whitespace
88 d2d5c360 Sofia Papagiannaki
        full_path = full_path.replace(' ', '%20')
89 ec1b8d3e Sofia Papagiannaki
        
90 3f5b02c7 Sofia Papagiannaki
        kwargs = {}
91 25c3841c Sofia Papagiannaki
        for k,v in headers.items():
92 25c3841c Sofia Papagiannaki
            headers.pop(k)
93 25c3841c Sofia Papagiannaki
            k = k.replace('_', '-')
94 25c3841c Sofia Papagiannaki
            headers[k] = v
95 25c3841c Sofia Papagiannaki
        
96 25c3841c Sofia Papagiannaki
        kwargs['headers'] = headers
97 bcb7c5a8 Sofia Papagiannaki
        kwargs['headers']['X-Auth-Token'] = self.token
98 3f5b02c7 Sofia Papagiannaki
        if body:
99 3f5b02c7 Sofia Papagiannaki
            kwargs['body'] = body
100 cd6ada1d Sofia Papagiannaki
            kwargs['headers'].setdefault('content-type',
101 cd6ada1d Sofia Papagiannaki
                                         'application/octet-stream')
102 25c3841c Sofia Papagiannaki
        kwargs['headers'].setdefault('content-length', len(body) if body else 0)
103 ae75584f Sofia Papagiannaki
        kwargs['headers'] = _encode_headers(kwargs['headers'])
104 ae75584f Sofia Papagiannaki
        #print '#', method, full_path, kwargs
105 ae75584f Sofia Papagiannaki
        conn.request(method, full_path, **kwargs)
106 ae75584f Sofia Papagiannaki
        
107 ae75584f Sofia Papagiannaki
        #try:
108 ae75584f Sofia Papagiannaki
        #    conn.request(method, full_path, **kwargs)
109 ae75584f Sofia Papagiannaki
        #except socket.error, e:
110 ae75584f Sofia Papagiannaki
        #    print '###', e[0], conn.auto_open
111 ae75584f Sofia Papagiannaki
        #    raise Fault(status=503)
112 e3fd7f91 Sofia Papagiannaki
            
113 3f5b02c7 Sofia Papagiannaki
        resp = conn.getresponse()
114 3f5b02c7 Sofia Papagiannaki
        headers = dict(resp.getheaders())
115 3f5b02c7 Sofia Papagiannaki
        
116 3f5b02c7 Sofia Papagiannaki
        if self.verbose:
117 3f5b02c7 Sofia Papagiannaki
            print '%d %s' % (resp.status, resp.reason)
118 3f5b02c7 Sofia Papagiannaki
            for key, val in headers.items():
119 3f5b02c7 Sofia Papagiannaki
                print '%s: %s' % (key.capitalize(), val)
120 3f5b02c7 Sofia Papagiannaki
            print
121 3f5b02c7 Sofia Papagiannaki
        
122 615e561b Sofia Papagiannaki
        length = resp.getheader('content-length', None)
123 6cd1831a Sofia Papagiannaki
        data = resp.read(length)
124 3f5b02c7 Sofia Papagiannaki
        if self.debug:
125 3f5b02c7 Sofia Papagiannaki
            print data
126 3f5b02c7 Sofia Papagiannaki
            print
127 3f5b02c7 Sofia Papagiannaki
        
128 e3fd7f91 Sofia Papagiannaki
        if int(resp.status) in ERROR_CODES.keys():
129 cd6ada1d Sofia Papagiannaki
            #print '**', resp.status
130 e3fd7f91 Sofia Papagiannaki
            raise Fault(data, int(resp.status))
131 e3fd7f91 Sofia Papagiannaki
        
132 cd6ada1d Sofia Papagiannaki
        #print '**',  resp.status, headers, data
133 3f5b02c7 Sofia Papagiannaki
        return resp.status, headers, data
134 f7ab99df Sofia Papagiannaki
    
135 25c3841c Sofia Papagiannaki
    def delete(self, path, format='text', params={}):
136 25c3841c Sofia Papagiannaki
        return self._req('DELETE', path, format=format, params=params)
137 f7ab99df Sofia Papagiannaki
    
138 ae75584f Sofia Papagiannaki
    def get(self, path, format='text', headers={}, params={},
139 ae75584f Sofia Papagiannaki
            top_level_req=False):
140 615e561b Sofia Papagiannaki
        return self._req('GET', path, headers=headers, format=format,
141 ae75584f Sofia Papagiannaki
                        params=params, top_level_req=top_level_req)
142 f7ab99df Sofia Papagiannaki
    
143 25c3841c Sofia Papagiannaki
    def head(self, path, format='text', params={}):
144 ae75584f Sofia Papagiannaki
         return self._req('HEAD', path, format=format, params=params)
145 f7ab99df Sofia Papagiannaki
    
146 25c3841c Sofia Papagiannaki
    def post(self, path, body=None, format='text', headers=None, params={}):
147 615e561b Sofia Papagiannaki
        return self._req('POST', path, body, headers=headers, format=format,
148 6749c3bd Sofia Papagiannaki
                        params=params)
149 f7ab99df Sofia Papagiannaki
    
150 3f5b02c7 Sofia Papagiannaki
    def put(self, path, body=None, format='text', headers=None):
151 615e561b Sofia Papagiannaki
        return self._req('PUT', path, body, headers=headers, format=format)
152 f7ab99df Sofia Papagiannaki
    
153 ae75584f Sofia Papagiannaki
    def _list(self, path, format='text', params={}, top_level_req=False, 
154 ae75584f Sofia Papagiannaki
              **headers):
155 3f5b02c7 Sofia Papagiannaki
        status, headers, data = self.get(path, format=format, headers=headers,
156 ae75584f Sofia Papagiannaki
                                         params=params,
157 ae75584f Sofia Papagiannaki
                                         top_level_req=top_level_req)
158 f0eacc2c Sofia Papagiannaki
        if format == 'json':
159 bcb7c5a8 Sofia Papagiannaki
            data = json.loads(data) if data else ''
160 f0eacc2c Sofia Papagiannaki
        elif format == 'xml':
161 f0eacc2c Sofia Papagiannaki
            data = minidom.parseString(data)
162 ec1b8d3e Sofia Papagiannaki
        else:
163 25c3841c Sofia Papagiannaki
            data = data.strip().split('\n') if data else ''
164 3f5b02c7 Sofia Papagiannaki
        return data
165 f7ab99df Sofia Papagiannaki
    
166 25c3841c Sofia Papagiannaki
    def _get_metadata(self, path, prefix=None, params={}):
167 d2d5c360 Sofia Papagiannaki
        status, headers, data = self.head(path, params=params)
168 f7ab99df Sofia Papagiannaki
        prefixlen = len(prefix) if prefix else 0
169 3f5b02c7 Sofia Papagiannaki
        meta = {}
170 3f5b02c7 Sofia Papagiannaki
        for key, val in headers.items():
171 0ea1dcc4 Sofia Papagiannaki
            if prefix and not key.startswith(prefix):
172 0ea1dcc4 Sofia Papagiannaki
                continue
173 0ea1dcc4 Sofia Papagiannaki
            elif prefix and key.startswith(prefix):
174 3f5b02c7 Sofia Papagiannaki
                key = key[prefixlen:]
175 0ea1dcc4 Sofia Papagiannaki
            meta[key] = val
176 3f5b02c7 Sofia Papagiannaki
        return meta
177 f7ab99df Sofia Papagiannaki
    
178 25c3841c Sofia Papagiannaki
    def _filter(self, l, d):
179 f7ab99df Sofia Papagiannaki
        """
180 25c3841c Sofia Papagiannaki
        filter out from l elements having the metadata values provided
181 f7ab99df Sofia Papagiannaki
        """
182 25c3841c Sofia Papagiannaki
        ll = l
183 25c3841c Sofia Papagiannaki
        for elem in l:
184 25c3841c Sofia Papagiannaki
            if type(elem) == types.DictionaryType:
185 25c3841c Sofia Papagiannaki
                for key in d.keys():
186 25c3841c Sofia Papagiannaki
                    k = 'x_object_meta_%s' % key
187 25c3841c Sofia Papagiannaki
                    if k in elem.keys() and elem[k] == d[key]:
188 25c3841c Sofia Papagiannaki
                        ll.remove(elem)
189 25c3841c Sofia Papagiannaki
                        break
190 25c3841c Sofia Papagiannaki
        return ll
191 25c3841c Sofia Papagiannaki
    
192 25c3841c Sofia Papagiannaki
class OOS_Client(Client):
193 f0eacc2c Sofia Papagiannaki
    """Openstack Object Storage Client"""
194 25c3841c Sofia Papagiannaki
    
195 25c3841c Sofia Papagiannaki
    def _update_metadata(self, path, entity, **meta):
196 25c3841c Sofia Papagiannaki
        """adds new and updates the values of previously set metadata"""
197 25c3841c Sofia Papagiannaki
        ex_meta = self.retrieve_account_metadata(restricted=True)
198 25c3841c Sofia Papagiannaki
        ex_meta.update(meta)
199 f7ab99df Sofia Papagiannaki
        headers = {}
200 6749c3bd Sofia Papagiannaki
        prefix = 'x-%s-meta-' % entity
201 25c3841c Sofia Papagiannaki
        for k,v in ex_meta.items():
202 6749c3bd Sofia Papagiannaki
            k = '%s%s' % (prefix, k)
203 6749c3bd Sofia Papagiannaki
            headers[k] = v
204 cd6ada1d Sofia Papagiannaki
        return self.post(path, headers=headers)
205 f7ab99df Sofia Papagiannaki
    
206 b9ca81a0 Sofia Papagiannaki
    def _reset_metadata(self, path, entity, **meta):
207 b9ca81a0 Sofia Papagiannaki
        """
208 b9ca81a0 Sofia Papagiannaki
        overwrites all user defined metadata
209 b9ca81a0 Sofia Papagiannaki
        """
210 b9ca81a0 Sofia Papagiannaki
        headers = {}
211 b9ca81a0 Sofia Papagiannaki
        prefix = 'x-%s-meta-' % entity
212 b9ca81a0 Sofia Papagiannaki
        for k,v in meta.items():
213 b9ca81a0 Sofia Papagiannaki
            k = '%s%s' % (prefix, k)
214 b9ca81a0 Sofia Papagiannaki
            headers[k] = v
215 b9ca81a0 Sofia Papagiannaki
        return self.post(path, headers=headers)
216 b9ca81a0 Sofia Papagiannaki
    
217 f7ab99df Sofia Papagiannaki
    def _delete_metadata(self, path, entity, meta=[]):
218 25c3841c Sofia Papagiannaki
        """delete previously set metadata"""
219 25c3841c Sofia Papagiannaki
        ex_meta = self.retrieve_account_metadata(restricted=True)
220 f7ab99df Sofia Papagiannaki
        headers = {}
221 615e561b Sofia Papagiannaki
        prefix = 'x-%s-meta-' % entity
222 25c3841c Sofia Papagiannaki
        for k in ex_meta.keys():
223 25c3841c Sofia Papagiannaki
            if k in meta:
224 25c3841c Sofia Papagiannaki
                headers['%s%s' % (prefix, k)] = ex_meta[k]
225 615e561b Sofia Papagiannaki
        return self.post(path, headers=headers)
226 f7ab99df Sofia Papagiannaki
    
227 3f5b02c7 Sofia Papagiannaki
    # Storage Account Services
228 f7ab99df Sofia Papagiannaki
    
229 ae75584f Sofia Papagiannaki
    def list_containers(self, format='text', limit=None, marker=None, params={},
230 25c3841c Sofia Papagiannaki
                        **headers):
231 25c3841c Sofia Papagiannaki
        """lists containers"""
232 25c3841c Sofia Papagiannaki
        params.update({'limit':limit, 'marker':marker})
233 f0eacc2c Sofia Papagiannaki
        return self._list('', format, params, **headers)
234 f7ab99df Sofia Papagiannaki
    
235 25c3841c Sofia Papagiannaki
    def retrieve_account_metadata(self, restricted=False, **params):
236 25c3841c Sofia Papagiannaki
        """returns the account metadata"""
237 f7ab99df Sofia Papagiannaki
        prefix = 'x-account-meta-' if restricted else None
238 25c3841c Sofia Papagiannaki
        return self._get_metadata('', prefix, params)
239 f7ab99df Sofia Papagiannaki
    
240 3f5b02c7 Sofia Papagiannaki
    def update_account_metadata(self, **meta):
241 25c3841c Sofia Papagiannaki
        """updates the account metadata"""
242 615e561b Sofia Papagiannaki
        return self._update_metadata('', 'account', **meta)
243 f7ab99df Sofia Papagiannaki
        
244 f7ab99df Sofia Papagiannaki
    def delete_account_metadata(self, meta=[]):
245 25c3841c Sofia Papagiannaki
        """deletes the account metadata"""
246 615e561b Sofia Papagiannaki
        return self._delete_metadata('', 'account', meta)
247 f7ab99df Sofia Papagiannaki
    
248 b9ca81a0 Sofia Papagiannaki
    def reset_account_metadata(self, **meta):
249 b9ca81a0 Sofia Papagiannaki
        """resets account metadata"""
250 b9ca81a0 Sofia Papagiannaki
        return self._reset_metadata('', 'account', **meta)
251 b9ca81a0 Sofia Papagiannaki
    
252 3f5b02c7 Sofia Papagiannaki
    # Storage Container Services
253 f7ab99df Sofia Papagiannaki
    
254 a4c10cbc Sofia Papagiannaki
    def _filter_trashed(self, l):
255 a4c10cbc Sofia Papagiannaki
        return self._filter(l, {'trash':'true'})
256 a4c10cbc Sofia Papagiannaki
    
257 ae75584f Sofia Papagiannaki
    def list_objects(self, container, format='text', limit=None, marker=None,
258 25c3841c Sofia Papagiannaki
                     prefix=None, delimiter=None, path=None,
259 25c3841c Sofia Papagiannaki
                     include_trashed=False, params={}, **headers):
260 25c3841c Sofia Papagiannaki
        """returns a list with the container objects"""
261 25c3841c Sofia Papagiannaki
        params.update({'limit':limit, 'marker':marker, 'prefix':prefix,
262 25c3841c Sofia Papagiannaki
                       'delimiter':delimiter, 'path':path})
263 f0eacc2c Sofia Papagiannaki
        l = self._list('/' + container, format, params, **headers)
264 f0eacc2c Sofia Papagiannaki
        #TODO support filter trashed with xml also
265 f0eacc2c Sofia Papagiannaki
        if format != 'xml' and not include_trashed:
266 a4c10cbc Sofia Papagiannaki
            l = self._filter_trashed(l)
267 a4c10cbc Sofia Papagiannaki
        return l
268 f7ab99df Sofia Papagiannaki
    
269 25c3841c Sofia Papagiannaki
    def create_container(self, container, **meta):
270 25c3841c Sofia Papagiannaki
        """creates a container"""
271 25c3841c Sofia Papagiannaki
        headers = {}
272 bcb7c5a8 Sofia Papagiannaki
        for k,v in meta.items():
273 615e561b Sofia Papagiannaki
            headers['x-container-meta-%s' %k.strip().upper()] = v.strip()
274 ec1b8d3e Sofia Papagiannaki
        status, header, data = self.put('/' + container, headers=headers)
275 3f5b02c7 Sofia Papagiannaki
        if status == 202:
276 3f5b02c7 Sofia Papagiannaki
            return False
277 3f5b02c7 Sofia Papagiannaki
        elif status != 201:
278 e3fd7f91 Sofia Papagiannaki
            raise Fault(data, int(status))
279 3f5b02c7 Sofia Papagiannaki
        return True
280 f7ab99df Sofia Papagiannaki
    
281 25c3841c Sofia Papagiannaki
    def delete_container(self, container, params={}):
282 25c3841c Sofia Papagiannaki
        """deletes a container"""
283 25c3841c Sofia Papagiannaki
        return self.delete('/' + container, params=params)
284 f7ab99df Sofia Papagiannaki
    
285 25c3841c Sofia Papagiannaki
    def retrieve_container_metadata(self, container, restricted=False, **params):
286 25c3841c Sofia Papagiannaki
        """returns the container metadata"""
287 f7ab99df Sofia Papagiannaki
        prefix = 'x-container-meta-' if restricted else None
288 25c3841c Sofia Papagiannaki
        return self._get_metadata('/%s' % container, prefix, params)
289 f7ab99df Sofia Papagiannaki
    
290 3f5b02c7 Sofia Papagiannaki
    def update_container_metadata(self, container, **meta):
291 25c3841c Sofia Papagiannaki
        """unpdates the container metadata"""
292 615e561b Sofia Papagiannaki
        return self._update_metadata('/' + container, 'container', **meta)
293 f7ab99df Sofia Papagiannaki
        
294 f7ab99df Sofia Papagiannaki
    def delete_container_metadata(self, container, meta=[]):
295 25c3841c Sofia Papagiannaki
        """deletes the container metadata"""
296 f7ab99df Sofia Papagiannaki
        path = '/%s' % (container)
297 615e561b Sofia Papagiannaki
        return self._delete_metadata(path, 'container', meta)
298 f7ab99df Sofia Papagiannaki
    
299 3f5b02c7 Sofia Papagiannaki
    # Storage Object Services
300 f7ab99df Sofia Papagiannaki
    
301 f0eacc2c Sofia Papagiannaki
    def request_object(self, container, object, format='text', params={},
302 25c3841c Sofia Papagiannaki
                        **headers):
303 25c3841c Sofia Papagiannaki
        """returns tuple containing the status, headers and data response for an object request"""
304 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
305 8fe01d72 Sofia Papagiannaki
        status, headers, data = self.get(path, format, headers, params)
306 25c3841c Sofia Papagiannaki
        return status, headers, data
307 25c3841c Sofia Papagiannaki
    
308 f0eacc2c Sofia Papagiannaki
    def retrieve_object(self, container, object, format='text', params={},
309 25c3841c Sofia Papagiannaki
                             **headers):
310 25c3841c Sofia Papagiannaki
        """returns an object's data"""
311 f0eacc2c Sofia Papagiannaki
        t = self.request_object(container, object, format, params, **headers)
312 25c3841c Sofia Papagiannaki
        return t[2]
313 f7ab99df Sofia Papagiannaki
    
314 f7ab99df Sofia Papagiannaki
    def create_directory_marker(self, container, object):
315 25c3841c Sofia Papagiannaki
        """creates a dierectory marker"""
316 f7ab99df Sofia Papagiannaki
        if not object:
317 f7ab99df Sofia Papagiannaki
            raise Fault('Directory markers have to be nested in a container')
318 7912c553 Sofia Papagiannaki
        h = {'content_type':'application/directory'}
319 25c3841c Sofia Papagiannaki
        return self.create_zero_length_object(container, object, **h)
320 f7ab99df Sofia Papagiannaki
    
321 25c3841c Sofia Papagiannaki
    def create_object(self, container, object, f=stdin, format='text', meta={},
322 25c3841c Sofia Papagiannaki
                      etag=None, content_type=None, content_encoding=None,
323 25c3841c Sofia Papagiannaki
                      content_disposition=None, **headers):
324 cd6ada1d Sofia Papagiannaki
        """creates a zero-length object"""
325 615e561b Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
326 25c3841c Sofia Papagiannaki
        for k, v  in headers.items():
327 25c3841c Sofia Papagiannaki
            if not v:
328 25c3841c Sofia Papagiannaki
                headers.pop(k)
329 25c3841c Sofia Papagiannaki
        
330 25c3841c Sofia Papagiannaki
        l = ['etag', 'content_encoding', 'content_disposition', 'content_type']
331 25c3841c Sofia Papagiannaki
        l = [elem for elem in l if eval(elem)]
332 25c3841c Sofia Papagiannaki
        for elem in l:
333 25c3841c Sofia Papagiannaki
            headers.update({elem:eval(elem)})
334 25c3841c Sofia Papagiannaki
            
335 615e561b Sofia Papagiannaki
        for k,v in meta.items():
336 615e561b Sofia Papagiannaki
            headers['x-object-meta-%s' %k.strip()] = v.strip()
337 25c3841c Sofia Papagiannaki
        data = f.read() if f else None
338 25c3841c Sofia Papagiannaki
        return self.put(path, data, format, headers=headers)
339 615e561b Sofia Papagiannaki
    
340 cd6ada1d Sofia Papagiannaki
    def create_zero_length_object(self, container, object, meta={}, etag=None,
341 cd6ada1d Sofia Papagiannaki
                                  content_type=None, content_encoding=None,
342 cd6ada1d Sofia Papagiannaki
                                  content_disposition=None, **headers):
343 cd6ada1d Sofia Papagiannaki
        args = locals()
344 cd6ada1d Sofia Papagiannaki
        for elem in ['self', 'container', 'headers']:
345 cd6ada1d Sofia Papagiannaki
            args.pop(elem)
346 cd6ada1d Sofia Papagiannaki
        args.update(headers)
347 cd6ada1d Sofia Papagiannaki
        return self.create_object(container, f=None, **args)
348 cd6ada1d Sofia Papagiannaki
    
349 25c3841c Sofia Papagiannaki
    def update_object(self, container, object, f=stdin, offset=None, meta={},
350 25c3841c Sofia Papagiannaki
                      content_length=None, content_type=None,
351 25c3841c Sofia Papagiannaki
                      content_encoding=None, content_disposition=None,
352 25c3841c Sofia Papagiannaki
                      **headers):
353 ec1b8d3e Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
354 25c3841c Sofia Papagiannaki
        for k, v  in headers.items():
355 25c3841c Sofia Papagiannaki
            if not v:
356 25c3841c Sofia Papagiannaki
                headers.pop(k)
357 25c3841c Sofia Papagiannaki
        
358 25c3841c Sofia Papagiannaki
        l = ['content_encoding', 'content_disposition', 'content_type',
359 25c3841c Sofia Papagiannaki
             'content_length']
360 25c3841c Sofia Papagiannaki
        l = [elem for elem in l if eval(elem)]
361 25c3841c Sofia Papagiannaki
        for elem in l:
362 25c3841c Sofia Papagiannaki
            headers.update({elem:eval(elem)})
363 25c3841c Sofia Papagiannaki
            
364 25c3841c Sofia Papagiannaki
        if 'content_range' not in headers.keys():
365 25c3841c Sofia Papagiannaki
            if offset != None:
366 25c3841c Sofia Papagiannaki
                headers['content_range'] = 'bytes %s-/*' % offset
367 25c3841c Sofia Papagiannaki
            else:
368 25c3841c Sofia Papagiannaki
                headers['content_range'] = 'bytes */*'
369 25c3841c Sofia Papagiannaki
            
370 bcb7c5a8 Sofia Papagiannaki
        for k,v in meta.items():
371 615e561b Sofia Papagiannaki
            headers['x-object-meta-%s' %k.strip()] = v.strip()
372 25c3841c Sofia Papagiannaki
        data = f.read() if f else None
373 25c3841c Sofia Papagiannaki
        return self.post(path, data, headers=headers)
374 f7ab99df Sofia Papagiannaki
    
375 ec1b8d3e Sofia Papagiannaki
    def _change_obj_location(self, src_container, src_object, dst_container,
376 7812e1f9 Sofia Papagiannaki
                             dst_object, remove=False, meta={}, **headers):
377 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (dst_container, dst_object)
378 7812e1f9 Sofia Papagiannaki
        headers = {} if not headers else headers
379 615e561b Sofia Papagiannaki
        for k, v in meta.items():
380 ae75584f Sofia Papagiannaki
            headers['x-object-meta-%s' % k] = v
381 ec1b8d3e Sofia Papagiannaki
        if remove:
382 615e561b Sofia Papagiannaki
            headers['x-move-from'] = '/%s/%s' % (src_container, src_object)
383 ec1b8d3e Sofia Papagiannaki
        else:
384 615e561b Sofia Papagiannaki
            headers['x-copy-from'] = '/%s/%s' % (src_container, src_object)
385 7812e1f9 Sofia Papagiannaki
        headers['content_length'] = 0
386 615e561b Sofia Papagiannaki
        return self.put(path, headers=headers)
387 f7ab99df Sofia Papagiannaki
    
388 7812e1f9 Sofia Papagiannaki
    def copy_object(self, src_container, src_object, dst_container, dst_object,
389 7812e1f9 Sofia Papagiannaki
                    meta, **headers):
390 7812e1f9 Sofia Papagiannaki
        """copies an object"""
391 615e561b Sofia Papagiannaki
        return self._change_obj_location(src_container, src_object,
392 7812e1f9 Sofia Papagiannaki
                                   dst_container, dst_object, remove=False,
393 7812e1f9 Sofia Papagiannaki
                                   meta=meta, **headers)
394 f7ab99df Sofia Papagiannaki
    
395 ec1b8d3e Sofia Papagiannaki
    def move_object(self, src_container, src_object, dst_container,
396 7812e1f9 Sofia Papagiannaki
                             dst_object, meta={}, **headers):
397 7812e1f9 Sofia Papagiannaki
        """moves an object"""
398 615e561b Sofia Papagiannaki
        return self._change_obj_location(src_container, src_object,
399 7812e1f9 Sofia Papagiannaki
                                         dst_container, dst_object, remove=True,
400 7812e1f9 Sofia Papagiannaki
                                         meta=meta, **headers)
401 f7ab99df Sofia Papagiannaki
    
402 25c3841c Sofia Papagiannaki
    def delete_object(self, container, object, params={}):
403 7812e1f9 Sofia Papagiannaki
        """deletes an object"""
404 25c3841c Sofia Papagiannaki
        return self.delete('/%s/%s' % (container, object), params=params)
405 f7ab99df Sofia Papagiannaki
    
406 8fe01d72 Sofia Papagiannaki
    def retrieve_object_metadata(self, container, object, restricted=False,
407 8fe01d72 Sofia Papagiannaki
                                 version=None):
408 615e561b Sofia Papagiannaki
        """
409 615e561b Sofia Papagiannaki
        set restricted to True to get only user defined metadata
410 615e561b Sofia Papagiannaki
        """
411 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
412 f7ab99df Sofia Papagiannaki
        prefix = 'x-object-meta-' if restricted else None
413 25c3841c Sofia Papagiannaki
        params = {'version':version} if version else {}
414 8fe01d72 Sofia Papagiannaki
        return self._get_metadata(path, prefix, params=params)
415 f7ab99df Sofia Papagiannaki
    
416 3f5b02c7 Sofia Papagiannaki
    def update_object_metadata(self, container, object, **meta):
417 3f5b02c7 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
418 615e561b Sofia Papagiannaki
        return self._update_metadata(path, 'object', **meta)
419 f7ab99df Sofia Papagiannaki
    
420 f7ab99df Sofia Papagiannaki
    def delete_object_metadata(self, container, object, meta=[]):
421 f7ab99df Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
422 615e561b Sofia Papagiannaki
        return self._delete_metadata(path, 'object', meta)
423 f7ab99df Sofia Papagiannaki
    
424 25c3841c Sofia Papagiannaki
class Pithos_Client(OOS_Client):
425 25c3841c Sofia Papagiannaki
    """Pithos Storage Client. Extends OOS_Client"""
426 25c3841c Sofia Papagiannaki
    
427 25c3841c Sofia Papagiannaki
    def _chunked_transfer(self, path, method='PUT', f=stdin, headers=None,
428 25c3841c Sofia Papagiannaki
                          blocksize=1024):
429 25c3841c Sofia Papagiannaki
        """perfomrs a chunked request"""
430 25c3841c Sofia Papagiannaki
        http = HTTPConnection(self.host)
431 25c3841c Sofia Papagiannaki
        
432 25c3841c Sofia Papagiannaki
        # write header
433 25c3841c Sofia Papagiannaki
        path = '/%s/%s%s' % (self.api, self.account, path)
434 25c3841c Sofia Papagiannaki
        http.putrequest(method, path)
435 25c3841c Sofia Papagiannaki
        http.putheader('x-auth-token', self.token)
436 25c3841c Sofia Papagiannaki
        http.putheader('content-type', 'application/octet-stream')
437 25c3841c Sofia Papagiannaki
        http.putheader('transfer-encoding', 'chunked')
438 25c3841c Sofia Papagiannaki
        if headers:
439 25c3841c Sofia Papagiannaki
            for header,value in headers.items():
440 25c3841c Sofia Papagiannaki
                http.putheader(header, value)
441 25c3841c Sofia Papagiannaki
        http.endheaders()
442 25c3841c Sofia Papagiannaki
        
443 25c3841c Sofia Papagiannaki
        # write body
444 25c3841c Sofia Papagiannaki
        data = ''
445 25c3841c Sofia Papagiannaki
        while True:
446 25c3841c Sofia Papagiannaki
            if f.closed:
447 25c3841c Sofia Papagiannaki
                break
448 25c3841c Sofia Papagiannaki
            block = f.read(blocksize)
449 25c3841c Sofia Papagiannaki
            if block == '':
450 25c3841c Sofia Papagiannaki
                break
451 ae75584f Sofia Papagiannaki
            data = '%x\r\n%s\r\n' % (len(block), block)
452 25c3841c Sofia Papagiannaki
            try:
453 25c3841c Sofia Papagiannaki
                http.send(data)
454 25c3841c Sofia Papagiannaki
            except:
455 25c3841c Sofia Papagiannaki
                #retry
456 25c3841c Sofia Papagiannaki
                http.send(data)
457 ae75584f Sofia Papagiannaki
        data = '0\r\n\r\n'
458 25c3841c Sofia Papagiannaki
        try:
459 25c3841c Sofia Papagiannaki
            http.send(data)
460 25c3841c Sofia Papagiannaki
        except:
461 25c3841c Sofia Papagiannaki
            #retry
462 25c3841c Sofia Papagiannaki
            http.send(data)
463 25c3841c Sofia Papagiannaki
        
464 25c3841c Sofia Papagiannaki
        # get response
465 25c3841c Sofia Papagiannaki
        resp = http.getresponse()
466 25c3841c Sofia Papagiannaki
        
467 25c3841c Sofia Papagiannaki
        headers = dict(resp.getheaders())
468 25c3841c Sofia Papagiannaki
        
469 25c3841c Sofia Papagiannaki
        if self.verbose:
470 25c3841c Sofia Papagiannaki
            print '%d %s' % (resp.status, resp.reason)
471 25c3841c Sofia Papagiannaki
            for key, val in headers.items():
472 25c3841c Sofia Papagiannaki
                print '%s: %s' % (key.capitalize(), val)
473 25c3841c Sofia Papagiannaki
            print
474 25c3841c Sofia Papagiannaki
        
475 25c3841c Sofia Papagiannaki
        length = resp.getheader('Content-length', None)
476 25c3841c Sofia Papagiannaki
        data = resp.read(length)
477 25c3841c Sofia Papagiannaki
        if self.debug:
478 25c3841c Sofia Papagiannaki
            print data
479 25c3841c Sofia Papagiannaki
            print
480 25c3841c Sofia Papagiannaki
        
481 25c3841c Sofia Papagiannaki
        if int(resp.status) in ERROR_CODES.keys():
482 25c3841c Sofia Papagiannaki
            raise Fault(data, int(resp.status))
483 25c3841c Sofia Papagiannaki
        
484 25c3841c Sofia Papagiannaki
        #print '*',  resp.status, headers, data
485 25c3841c Sofia Papagiannaki
        return resp.status, headers, data
486 25c3841c Sofia Papagiannaki
    
487 25c3841c Sofia Papagiannaki
    def _update_metadata(self, path, entity, **meta):
488 25c3841c Sofia Papagiannaki
        """
489 25c3841c Sofia Papagiannaki
        adds new and updates the values of previously set metadata
490 25c3841c Sofia Papagiannaki
        """
491 25c3841c Sofia Papagiannaki
        params = {'update':None}
492 25c3841c Sofia Papagiannaki
        headers = {}
493 25c3841c Sofia Papagiannaki
        prefix = 'x-%s-meta-' % entity
494 25c3841c Sofia Papagiannaki
        for k,v in meta.items():
495 25c3841c Sofia Papagiannaki
            k = '%s%s' % (prefix, k)
496 25c3841c Sofia Papagiannaki
            headers[k] = v
497 25c3841c Sofia Papagiannaki
        return self.post(path, headers=headers, params=params)
498 25c3841c Sofia Papagiannaki
    
499 25c3841c Sofia Papagiannaki
    def _delete_metadata(self, path, entity, meta=[]):
500 f7ab99df Sofia Papagiannaki
        """
501 25c3841c Sofia Papagiannaki
        delete previously set metadata
502 f7ab99df Sofia Papagiannaki
        """
503 25c3841c Sofia Papagiannaki
        params = {'update':None}
504 25c3841c Sofia Papagiannaki
        headers = {}
505 25c3841c Sofia Papagiannaki
        prefix = 'x-%s-meta-' % entity
506 25c3841c Sofia Papagiannaki
        for m in meta:
507 f0eacc2c Sofia Papagiannaki
            headers['%s%s' % (prefix, m)] = ''
508 25c3841c Sofia Papagiannaki
        return self.post(path, headers=headers, params=params)
509 25c3841c Sofia Papagiannaki
    
510 25c3841c Sofia Papagiannaki
    # Storage Account Services
511 25c3841c Sofia Papagiannaki
    
512 f0eacc2c Sofia Papagiannaki
    def list_containers(self, format='text', if_modified_since=None,
513 25c3841c Sofia Papagiannaki
                        if_unmodified_since=None, limit=1000, marker=None,
514 25c3841c Sofia Papagiannaki
                        until=None):
515 25c3841c Sofia Papagiannaki
        """returns a list with the account containers"""
516 ae75584f Sofia Papagiannaki
        params = {'until':until} if until else {}
517 25c3841c Sofia Papagiannaki
        headers = {'if-modified-since':if_modified_since,
518 25c3841c Sofia Papagiannaki
                   'if-unmodified-since':if_unmodified_since}
519 f0eacc2c Sofia Papagiannaki
        return OOS_Client.list_containers(self, format=format, limit=limit,
520 25c3841c Sofia Papagiannaki
                                          marker=marker, params=params,
521 25c3841c Sofia Papagiannaki
                                          **headers)
522 25c3841c Sofia Papagiannaki
    
523 25c3841c Sofia Papagiannaki
    def retrieve_account_metadata(self, restricted=False, until=None):
524 25c3841c Sofia Papagiannaki
        """returns the account metadata"""
525 25c3841c Sofia Papagiannaki
        params = {'until':until} if until else {}
526 25c3841c Sofia Papagiannaki
        return OOS_Client.retrieve_account_metadata(self, restricted=restricted,
527 25c3841c Sofia Papagiannaki
                                                   **params)
528 25c3841c Sofia Papagiannaki
    
529 25c3841c Sofia Papagiannaki
    def set_account_groups(self, **groups):
530 25c3841c Sofia Papagiannaki
        """create account groups"""
531 25c3841c Sofia Papagiannaki
        headers = {}
532 ae75584f Sofia Papagiannaki
        for k, v in groups.items():
533 ae75584f Sofia Papagiannaki
            headers['x-account-group-%s' % k] = v
534 25c3841c Sofia Papagiannaki
        params = {'update':None}
535 25c3841c Sofia Papagiannaki
        return self.post('', headers=headers, params=params)
536 25c3841c Sofia Papagiannaki
    
537 b9ca81a0 Sofia Papagiannaki
    def retrieve_account_groups(self):
538 b9ca81a0 Sofia Papagiannaki
        """returns the account groups"""
539 b9ca81a0 Sofia Papagiannaki
        meta = self.retrieve_account_metadata()
540 b9ca81a0 Sofia Papagiannaki
        prefix = 'x-account-group-'
541 b9ca81a0 Sofia Papagiannaki
        prefixlen = len(prefix)
542 b9ca81a0 Sofia Papagiannaki
        groups = {}
543 b9ca81a0 Sofia Papagiannaki
        for key, val in meta.items():
544 b9ca81a0 Sofia Papagiannaki
            if prefix and not key.startswith(prefix):
545 b9ca81a0 Sofia Papagiannaki
                continue
546 b9ca81a0 Sofia Papagiannaki
            elif prefix and key.startswith(prefix):
547 b9ca81a0 Sofia Papagiannaki
                key = key[prefixlen:]
548 b9ca81a0 Sofia Papagiannaki
            groups[key] = val
549 b9ca81a0 Sofia Papagiannaki
        return groups
550 b9ca81a0 Sofia Papagiannaki
    
551 25c3841c Sofia Papagiannaki
    def unset_account_groups(self, groups=[]):
552 25c3841c Sofia Papagiannaki
        """delete account groups"""
553 25c3841c Sofia Papagiannaki
        headers = {}
554 25c3841c Sofia Papagiannaki
        for elem in groups:
555 25c3841c Sofia Papagiannaki
            headers['x-account-group-%s' % elem] = ''
556 25c3841c Sofia Papagiannaki
        params = {'update':None}
557 25c3841c Sofia Papagiannaki
        return self.post('', headers=headers, params=params)
558 25c3841c Sofia Papagiannaki
    
559 cd6ada1d Sofia Papagiannaki
    def reset_account_groups(self, **groups):
560 cd6ada1d Sofia Papagiannaki
        """overrides account groups"""
561 cd6ada1d Sofia Papagiannaki
        headers = {}
562 ae75584f Sofia Papagiannaki
        for k, v in groups.items():
563 ae75584f Sofia Papagiannaki
            v = v.strip()
564 ae75584f Sofia Papagiannaki
            headers['x-account-group-%s' % k] = v
565 cd6ada1d Sofia Papagiannaki
        meta = self.retrieve_account_metadata()
566 cd6ada1d Sofia Papagiannaki
        headers.update(meta)
567 cd6ada1d Sofia Papagiannaki
        return self.post('', headers=headers)
568 cd6ada1d Sofia Papagiannaki
    
569 25c3841c Sofia Papagiannaki
    # Storage Container Services
570 25c3841c Sofia Papagiannaki
    
571 ae75584f Sofia Papagiannaki
    def list_objects(self, container, format='text', limit=None, marker=None,
572 25c3841c Sofia Papagiannaki
                     prefix=None, delimiter=None, path=None,
573 25c3841c Sofia Papagiannaki
                     include_trashed=False, params={}, if_modified_since=None,
574 25c3841c Sofia Papagiannaki
                     if_unmodified_since=None, meta={}, until=None):
575 25c3841c Sofia Papagiannaki
        """returns a list with the container objects"""
576 25c3841c Sofia Papagiannaki
        params = {'until':until, 'meta':meta}
577 25c3841c Sofia Papagiannaki
        args = locals()
578 25c3841c Sofia Papagiannaki
        for elem in ['self', 'container', 'params', 'until', 'meta']:
579 25c3841c Sofia Papagiannaki
            args.pop(elem)
580 25c3841c Sofia Papagiannaki
        return OOS_Client.list_objects(self, container, params=params, 
581 25c3841c Sofia Papagiannaki
                                       **args)
582 25c3841c Sofia Papagiannaki
    
583 25c3841c Sofia Papagiannaki
    def retrieve_container_metadata(self, container, restricted=False,
584 25c3841c Sofia Papagiannaki
                                    until=None):
585 25c3841c Sofia Papagiannaki
        """returns container's metadata"""
586 25c3841c Sofia Papagiannaki
        params = {'until':until} if until else {}
587 25c3841c Sofia Papagiannaki
        return OOS_Client.retrieve_container_metadata(self, container,
588 25c3841c Sofia Papagiannaki
                                                      restricted=restricted,
589 25c3841c Sofia Papagiannaki
                                                      **params)
590 25c3841c Sofia Papagiannaki
    
591 25c3841c Sofia Papagiannaki
    def set_container_policies(self, container, **policies):
592 25c3841c Sofia Papagiannaki
        """sets containers policies"""
593 25c3841c Sofia Papagiannaki
        path = '/%s' % (container)
594 25c3841c Sofia Papagiannaki
        headers = {}
595 25c3841c Sofia Papagiannaki
        print ''
596 25c3841c Sofia Papagiannaki
        for key, val in policies.items():
597 25c3841c Sofia Papagiannaki
            headers['x-container-policy-%s' % key] = val
598 25c3841c Sofia Papagiannaki
        return self.post(path, headers=headers)
599 25c3841c Sofia Papagiannaki
    
600 25c3841c Sofia Papagiannaki
    def delete_container(self, container, until=None):
601 25c3841c Sofia Papagiannaki
        """deletes a container or the container history until the date provided"""
602 25c3841c Sofia Papagiannaki
        params = {'until':until} if until else {}
603 25c3841c Sofia Papagiannaki
        return OOS_Client.delete_container(self, container, params)
604 25c3841c Sofia Papagiannaki
    
605 25c3841c Sofia Papagiannaki
    # Storage Object Services
606 25c3841c Sofia Papagiannaki
    
607 f0eacc2c Sofia Papagiannaki
    def retrieve_object(self, container, object, params={}, format='text', range=None,
608 25c3841c Sofia Papagiannaki
                        if_range=None, if_match=None, if_none_match=None,
609 25c3841c Sofia Papagiannaki
                        if_modified_since=None, if_unmodified_since=None,
610 25c3841c Sofia Papagiannaki
                        **headers):
611 25c3841c Sofia Papagiannaki
        """returns an object"""
612 25c3841c Sofia Papagiannaki
        headers={}
613 25c3841c Sofia Papagiannaki
        l = ['range', 'if_range', 'if_match', 'if_none_match',
614 25c3841c Sofia Papagiannaki
             'if_modified_since', 'if_unmodified_since']
615 25c3841c Sofia Papagiannaki
        l = [elem for elem in l if eval(elem)]
616 25c3841c Sofia Papagiannaki
        for elem in l:
617 25c3841c Sofia Papagiannaki
            headers.update({elem:eval(elem)})
618 f0eacc2c Sofia Papagiannaki
        return OOS_Client.retrieve_object(self, container, object, format=format,
619 25c3841c Sofia Papagiannaki
                                          params=params, **headers)
620 25c3841c Sofia Papagiannaki
    
621 25c3841c Sofia Papagiannaki
    def retrieve_object_version(self, container, object, version, detail=False,
622 25c3841c Sofia Papagiannaki
                                range=None, if_range=None, if_match=None,
623 25c3841c Sofia Papagiannaki
                                if_none_match=None, if_modified_since=None,
624 25c3841c Sofia Papagiannaki
                                if_unmodified_since=None):
625 25c3841c Sofia Papagiannaki
        """returns a specific object version"""
626 25c3841c Sofia Papagiannaki
        args = locals()
627 25c3841c Sofia Papagiannaki
        l = ['self', 'container', 'object']
628 25c3841c Sofia Papagiannaki
        for elem in l:
629 25c3841c Sofia Papagiannaki
            args.pop(elem)
630 25c3841c Sofia Papagiannaki
        params = {'version':version}
631 25c3841c Sofia Papagiannaki
        return self.retrieve_object(container, object, params, **args)
632 25c3841c Sofia Papagiannaki
    
633 25c3841c Sofia Papagiannaki
    def retrieve_object_versionlist(self, container, object, range=None,
634 25c3841c Sofia Papagiannaki
                                    if_range=None, if_match=None,
635 25c3841c Sofia Papagiannaki
                                    if_none_match=None, if_modified_since=None,
636 25c3841c Sofia Papagiannaki
                                    if_unmodified_since=None):
637 25c3841c Sofia Papagiannaki
        """returns the object version list"""
638 25c3841c Sofia Papagiannaki
        args = locals()
639 25c3841c Sofia Papagiannaki
        l = ['self', 'container', 'object']
640 25c3841c Sofia Papagiannaki
        for elem in l:
641 25c3841c Sofia Papagiannaki
            args.pop(elem)
642 25c3841c Sofia Papagiannaki
            
643 25c3841c Sofia Papagiannaki
        return self.retrieve_object_version(container, object, version='list',
644 25c3841c Sofia Papagiannaki
                                            detail=True, **args)
645 25c3841c Sofia Papagiannaki
    
646 cd6ada1d Sofia Papagiannaki
    def create_zero_length_object(self, container, object, meta={},
647 cd6ada1d Sofia Papagiannaki
                      etag=None, content_type=None, content_encoding=None,
648 cd6ada1d Sofia Papagiannaki
                      content_disposition=None, x_object_manifest=None,
649 cd6ada1d Sofia Papagiannaki
                      x_object_sharing=None, x_object_public=None):
650 cd6ada1d Sofia Papagiannaki
        """createas a zero length object"""
651 cd6ada1d Sofia Papagiannaki
        args = locals()
652 cd6ada1d Sofia Papagiannaki
        for elem in ['self', 'container', 'object']:
653 cd6ada1d Sofia Papagiannaki
            args.pop(elem)
654 cd6ada1d Sofia Papagiannaki
        return OOS_Client.create_zero_length_object(self, container, object,
655 cd6ada1d Sofia Papagiannaki
                                                    **args)
656 cd6ada1d Sofia Papagiannaki
    
657 25c3841c Sofia Papagiannaki
    def create_object(self, container, object, f=stdin, meta={},
658 25c3841c Sofia Papagiannaki
                      etag=None, content_type=None, content_encoding=None,
659 25c3841c Sofia Papagiannaki
                      content_disposition=None, x_object_manifest=None,
660 25c3841c Sofia Papagiannaki
                      x_object_sharing=None, x_object_public=None):
661 25c3841c Sofia Papagiannaki
        """creates an object"""
662 25c3841c Sofia Papagiannaki
        args = locals()
663 25c3841c Sofia Papagiannaki
        for elem in ['self', 'container', 'object']:
664 25c3841c Sofia Papagiannaki
            args.pop(elem)
665 25c3841c Sofia Papagiannaki
        return OOS_Client.create_object(self, container, object, **args)
666 25c3841c Sofia Papagiannaki
        
667 25c3841c Sofia Papagiannaki
    def create_object_using_chunks(self, container, object, f=stdin,
668 25c3841c Sofia Papagiannaki
                                    blocksize=1024, meta={}, etag=None,
669 25c3841c Sofia Papagiannaki
                                    content_type=None, content_encoding=None,
670 25c3841c Sofia Papagiannaki
                                    content_disposition=None, 
671 25c3841c Sofia Papagiannaki
                                    x_object_sharing=None,
672 25c3841c Sofia Papagiannaki
                                    x_object_manifest=None, 
673 25c3841c Sofia Papagiannaki
                                    x_object_public=None):
674 25c3841c Sofia Papagiannaki
        """creates an object (incremental upload)"""
675 25c3841c Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
676 25c3841c Sofia Papagiannaki
        headers = {}
677 25c3841c Sofia Papagiannaki
        l = ['etag', 'content_type', 'content_encoding', 'content_disposition', 
678 25c3841c Sofia Papagiannaki
             'x_object_sharing', 'x_object_manifest', 'x_object_public']
679 25c3841c Sofia Papagiannaki
        l = [elem for elem in l if eval(elem)]
680 25c3841c Sofia Papagiannaki
        for elem in l:
681 25c3841c Sofia Papagiannaki
            headers.update({elem:eval(elem)})
682 25c3841c Sofia Papagiannaki
        
683 25c3841c Sofia Papagiannaki
        for k,v in meta.items():
684 ae75584f Sofia Papagiannaki
            v = v.strip()
685 ae75584f Sofia Papagiannaki
            headers['x-object-meta-%s' %k.strip()] = v
686 25c3841c Sofia Papagiannaki
        
687 25c3841c Sofia Papagiannaki
        return self._chunked_transfer(path, 'PUT', f, headers=headers,
688 25c3841c Sofia Papagiannaki
                                      blocksize=blocksize)
689 25c3841c Sofia Papagiannaki
    
690 25c3841c Sofia Papagiannaki
    def create_object_by_hashmap(container, object, f=stdin, format='json',
691 25c3841c Sofia Papagiannaki
                                 meta={}, etag=None, content_encoding=None,
692 25c3841c Sofia Papagiannaki
                                 content_disposition=None, content_type=None,
693 25c3841c Sofia Papagiannaki
                                 x_object_sharing=None, x_object_manifest=None,
694 25c3841c Sofia Papagiannaki
                                 x_object_public = None):
695 25c3841c Sofia Papagiannaki
        """creates an object by uploading hashes representing data instead of data"""
696 25c3841c Sofia Papagiannaki
        args = locals()
697 25c3841c Sofia Papagiannaki
        for elem in ['self', 'container', 'object']:
698 25c3841c Sofia Papagiannaki
            args.pop(elem)
699 25c3841c Sofia Papagiannaki
            
700 25c3841c Sofia Papagiannaki
        data = f.read() if f else None
701 25c3841c Sofia Papagiannaki
        if data and format == 'json':
702 25c3841c Sofia Papagiannaki
            try:
703 25c3841c Sofia Papagiannaki
                data = eval(data)
704 25c3841c Sofia Papagiannaki
                data = json.dumps(data)
705 25c3841c Sofia Papagiannaki
            except SyntaxError:
706 25c3841c Sofia Papagiannaki
                raise Fault('Invalid formatting')
707 25c3841c Sofia Papagiannaki
        
708 25c3841c Sofia Papagiannaki
        #TODO check with xml
709 25c3841c Sofia Papagiannaki
        return self.create_object(container, object, **args)
710 25c3841c Sofia Papagiannaki
    
711 25c3841c Sofia Papagiannaki
    def create_manifestation(self, container, object, manifest):
712 25c3841c Sofia Papagiannaki
        """creates a manifestation"""
713 25c3841c Sofia Papagiannaki
        headers={'x_object_manifest':manifest}
714 25c3841c Sofia Papagiannaki
        return self.create_object(container, object, f=None, **headers)
715 25c3841c Sofia Papagiannaki
    
716 25c3841c Sofia Papagiannaki
    def update_object(self, container, object, f=stdin, offset=None, meta={},
717 25c3841c Sofia Papagiannaki
                      content_length=None, content_type=None, content_range=None,
718 25c3841c Sofia Papagiannaki
                      content_encoding=None, content_disposition=None,
719 25c3841c Sofia Papagiannaki
                      x_object_bytes=None, x_object_manifest=None,
720 25c3841c Sofia Papagiannaki
                      x_object_sharing=None, x_object_public=None):
721 25c3841c Sofia Papagiannaki
        """updates an object"""
722 25c3841c Sofia Papagiannaki
        spath = '/%s/%s' % (container, object)
723 25c3841c Sofia Papagiannaki
        args = locals()
724 25c3841c Sofia Papagiannaki
        for elem in ['self', 'container', 'object']:
725 25c3841c Sofia Papagiannaki
            args.pop(elem)
726 25c3841c Sofia Papagiannaki
        
727 25c3841c Sofia Papagiannaki
        return OOS_Client.update_object(self, container, object, **args)
728 25c3841c Sofia Papagiannaki
        
729 25c3841c Sofia Papagiannaki
    def update_object_using_chunks(self, container, object, f=stdin,
730 25c3841c Sofia Papagiannaki
                                    blocksize=1024, offset=None, meta={},
731 25c3841c Sofia Papagiannaki
                                    content_type=None, content_encoding=None,
732 25c3841c Sofia Papagiannaki
                                    content_disposition=None, x_object_bytes=None,
733 25c3841c Sofia Papagiannaki
                                    x_object_manifest=None, x_object_sharing=None,
734 25c3841c Sofia Papagiannaki
                                    x_object_public=None):
735 25c3841c Sofia Papagiannaki
        """updates an object (incremental upload)"""
736 25c3841c Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
737 25c3841c Sofia Papagiannaki
        headers = {}
738 25c3841c Sofia Papagiannaki
        l = ['content_type', 'content_encoding', 'content_disposition',
739 25c3841c Sofia Papagiannaki
             'x_object_bytes', 'x_object_manifest', 'x_object_sharing',
740 25c3841c Sofia Papagiannaki
             'x_object_public']
741 25c3841c Sofia Papagiannaki
        l = [elem for elem in l if eval(elem)]
742 25c3841c Sofia Papagiannaki
        for elem in l:
743 25c3841c Sofia Papagiannaki
            headers.update({elem:eval(elem)})
744 25c3841c Sofia Papagiannaki
        
745 25c3841c Sofia Papagiannaki
        if offset != None:
746 25c3841c Sofia Papagiannaki
            headers['content_range'] = 'bytes %s-/*' % offset
747 25c3841c Sofia Papagiannaki
        else:
748 25c3841c Sofia Papagiannaki
            headers['content_range'] = 'bytes */*'
749 25c3841c Sofia Papagiannaki
        
750 25c3841c Sofia Papagiannaki
        for k,v in meta.items():
751 ae75584f Sofia Papagiannaki
            v = v.strip()
752 ae75584f Sofia Papagiannaki
            headers['x-object-meta-%s' %k.strip()] = v
753 25c3841c Sofia Papagiannaki
        
754 25c3841c Sofia Papagiannaki
        return self._chunked_transfer(path, 'POST', f, headers=headers,
755 25c3841c Sofia Papagiannaki
                                      blocksize=blocksize)
756 25c3841c Sofia Papagiannaki
    
757 25c3841c Sofia Papagiannaki
    def delete_object(self, container, object, until=None):
758 25c3841c Sofia Papagiannaki
        """deletes an object or the object history until the date provided"""
759 25c3841c Sofia Papagiannaki
        params = {'until':until} if until else {}
760 25c3841c Sofia Papagiannaki
        return OOS_Client.delete_object(self, container, object, params)
761 25c3841c Sofia Papagiannaki
    
762 25c3841c Sofia Papagiannaki
    def trash_object(self, container, object):
763 25c3841c Sofia Papagiannaki
        """trashes an object"""
764 f7ab99df Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
765 f7ab99df Sofia Papagiannaki
        meta = {'trash':'true'}
766 615e561b Sofia Papagiannaki
        return self._update_metadata(path, 'object', **meta)
767 f7ab99df Sofia Papagiannaki
    
768 f7ab99df Sofia Papagiannaki
    def restore_object(self, container, object):
769 25c3841c Sofia Papagiannaki
        """restores a trashed object"""
770 615e561b Sofia Papagiannaki
        return self.delete_object_metadata(container, object, ['trash'])
771 f89e3cf4 Sofia Papagiannaki
    
772 f89e3cf4 Sofia Papagiannaki
    def publish_object(self, container, object):
773 25c3841c Sofia Papagiannaki
        """sets a previously created object publicly accessible"""
774 f89e3cf4 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
775 25c3841c Sofia Papagiannaki
        headers = {'content_range':'bytes */*'}
776 7812e1f9 Sofia Papagiannaki
        headers['x_object_public'] = True
777 615e561b Sofia Papagiannaki
        return self.post(path, headers=headers)
778 f89e3cf4 Sofia Papagiannaki
    
779 f89e3cf4 Sofia Papagiannaki
    def unpublish_object(self, container, object):
780 25c3841c Sofia Papagiannaki
        """unpublish an object"""
781 f89e3cf4 Sofia Papagiannaki
        path = '/%s/%s' % (container, object)
782 25c3841c Sofia Papagiannaki
        headers = {'content_range':'bytes */*'}
783 7812e1f9 Sofia Papagiannaki
        headers['x_object_public'] = False
784 615e561b Sofia Papagiannaki
        return self.post(path, headers=headers)
785 7812e1f9 Sofia Papagiannaki
    
786 7812e1f9 Sofia Papagiannaki
    def _change_obj_location(self, src_container, src_object, dst_container,
787 7812e1f9 Sofia Papagiannaki
                             dst_object, remove=False, meta={}, **headers):
788 7812e1f9 Sofia Papagiannaki
        path = '/%s/%s' % (dst_container, dst_object)
789 7812e1f9 Sofia Papagiannaki
        headers = {} if not headers else headers
790 7812e1f9 Sofia Papagiannaki
        for k, v in meta.items():
791 ae75584f Sofia Papagiannaki
            headers['x-object-meta-%s' % k] = v
792 7812e1f9 Sofia Papagiannaki
        if remove:
793 7812e1f9 Sofia Papagiannaki
            headers['x-move-from'] = '/%s/%s' % (src_container, src_object)
794 7812e1f9 Sofia Papagiannaki
        else:
795 7812e1f9 Sofia Papagiannaki
            headers['x-copy-from'] = '/%s/%s' % (src_container, src_object)
796 7812e1f9 Sofia Papagiannaki
        headers['content_length'] = 0
797 7812e1f9 Sofia Papagiannaki
        return self.put(path, headers=headers)
798 7812e1f9 Sofia Papagiannaki
    
799 7812e1f9 Sofia Papagiannaki
    def copy_object(self, src_container, src_object, dst_container, dst_object,
800 7812e1f9 Sofia Papagiannaki
                    meta={}, public=False, version=None):
801 7812e1f9 Sofia Papagiannaki
        """copies an object"""
802 7812e1f9 Sofia Papagiannaki
        headers = {}
803 7812e1f9 Sofia Papagiannaki
        headers['x_object_public'] = public
804 7812e1f9 Sofia Papagiannaki
        if version:
805 7812e1f9 Sofia Papagiannaki
            headers['x_object_version'] = version
806 7812e1f9 Sofia Papagiannaki
        return OOS_Client.copy_object(self, src_container, src_object,
807 7812e1f9 Sofia Papagiannaki
                                      dst_container, dst_object, meta=meta,
808 7812e1f9 Sofia Papagiannaki
                                      **headers)
809 7812e1f9 Sofia Papagiannaki
    
810 7812e1f9 Sofia Papagiannaki
    def move_object(self, src_container, src_object, dst_container,
811 7812e1f9 Sofia Papagiannaki
                             dst_object, meta={}, public=False, version=None):
812 7812e1f9 Sofia Papagiannaki
        """moves an object"""
813 7812e1f9 Sofia Papagiannaki
        headers = {}
814 7812e1f9 Sofia Papagiannaki
        headers['x_object_public'] = public
815 7812e1f9 Sofia Papagiannaki
        if version:
816 7812e1f9 Sofia Papagiannaki
            headers['x_object_version'] = version
817 7812e1f9 Sofia Papagiannaki
        return OOS_Client.move_object(self, src_container, src_object,
818 7812e1f9 Sofia Papagiannaki
                                      dst_container, dst_object, meta=meta,
819 ae75584f Sofia Papagiannaki
                                      **headers)
820 ae75584f Sofia Papagiannaki
    
821 ae75584f Sofia Papagiannaki
    def list_shared_by_others(self, limit=None, marker=None, format='text'):
822 ae75584f Sofia Papagiannaki
         l = ['limit', 'marker']
823 ae75584f Sofia Papagiannaki
         params = {}
824 ae75584f Sofia Papagiannaki
         for elem in [elem for elem in l if eval(elem)]:
825 ae75584f Sofia Papagiannaki
             params[elem] = eval(elem)
826 ae75584f Sofia Papagiannaki
         return self._list('', format, params, top_level_req=True)
827 ae75584f Sofia Papagiannaki
    
828 ae75584f Sofia Papagiannaki
    def share_object(self, container, object, l, read=True):
829 ae75584f Sofia Papagiannaki
        action = 'read' if read else 'write'
830 ae75584f Sofia Papagiannaki
        sharing = '%s=%s' % (action, ','.join(l))
831 ae75584f Sofia Papagiannaki
        self.update_object(container, object, f=None, x_object_sharing=sharing)
832 ae75584f Sofia Papagiannaki
833 ae75584f Sofia Papagiannaki
def _encode_headers(headers):
834 ae75584f Sofia Papagiannaki
    h = {}
835 ae75584f Sofia Papagiannaki
    for k, v in headers.items():
836 ae75584f Sofia Papagiannaki
        k = urllib.quote(k)
837 ae75584f Sofia Papagiannaki
        if v and type(v) == types.StringType:
838 ae75584f Sofia Papagiannaki
            v = urllib.quote(v, '/=,-* :"')
839 ae75584f Sofia Papagiannaki
        h[k] = v
840 ae75584f Sofia Papagiannaki
    return h