Statistics
| Branch: | Tag: | Revision:

root / pithos / lib / client.py @ 7912c553

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