Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / pithos.py @ 5c72ad76

History | View | Annotate | Download (36.1 kB)

1 fce31e83 Stavros Sachtouris
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 d2cea1e2 Giorgos Verigakis
#
3 d2cea1e2 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 d2cea1e2 Giorgos Verigakis
# without modification, are permitted provided that the following
5 d2cea1e2 Giorgos Verigakis
# conditions are met:
6 d2cea1e2 Giorgos Verigakis
#
7 d2cea1e2 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 d2cea1e2 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 d2cea1e2 Giorgos Verigakis
#      disclaimer.
10 d2cea1e2 Giorgos Verigakis
#
11 d2cea1e2 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 d2cea1e2 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 d2cea1e2 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 d2cea1e2 Giorgos Verigakis
#      provided with the distribution.
15 d2cea1e2 Giorgos Verigakis
#
16 d2cea1e2 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 d2cea1e2 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 d2cea1e2 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 d2cea1e2 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 d2cea1e2 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 d2cea1e2 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 d2cea1e2 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 d2cea1e2 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 d2cea1e2 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 d2cea1e2 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 d2cea1e2 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 d2cea1e2 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 d2cea1e2 Giorgos Verigakis
#
29 d2cea1e2 Giorgos Verigakis
# The views and conclusions contained in the software and
30 d2cea1e2 Giorgos Verigakis
# documentation are those of the authors and should not be
31 d2cea1e2 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 d2cea1e2 Giorgos Verigakis
# or implied, of GRNET S.A.
33 d2cea1e2 Giorgos Verigakis
34 f27ed9a0 Stavros Sachtouris
from threading import enumerate as activethreads
35 435008b6 Stavros Sachtouris
36 3dabe5d2 Stavros Sachtouris
from os import fstat
37 64ab4c13 Stavros Sachtouris
from hashlib import new as newhashlib
38 e02728f9 Stavros Sachtouris
from time import time
39 a91e0293 Giorgos Verigakis
40 64ab4c13 Stavros Sachtouris
from binascii import hexlify
41 6a0b1658 Giorgos Verigakis
42 6069b53b Stavros Sachtouris
from kamaki.clients import SilentEvent, sendlog
43 c270fe96 Stavros Sachtouris
from kamaki.clients.pithos_rest_api import PithosRestAPI
44 c270fe96 Stavros Sachtouris
from kamaki.clients.storage import ClientError
45 c270fe96 Stavros Sachtouris
from kamaki.clients.utils import path4url, filter_in
46 1785ad41 Stavros Sachtouris
from StringIO import StringIO
47 6a0b1658 Giorgos Verigakis
48 3dabe5d2 Stavros Sachtouris
49 4375e020 Stavros Sachtouris
def _pithos_hash(block, blockhash):
50 64ab4c13 Stavros Sachtouris
    h = newhashlib(blockhash)
51 6a0b1658 Giorgos Verigakis
    h.update(block.rstrip('\x00'))
52 6a0b1658 Giorgos Verigakis
    return h.hexdigest()
53 6a0b1658 Giorgos Verigakis
54 3dabe5d2 Stavros Sachtouris
55 642f1bbd Stavros Sachtouris
def _range_up(start, end, a_range):
56 642f1bbd Stavros Sachtouris
    if a_range:
57 642f1bbd Stavros Sachtouris
        (rstart, rend) = a_range.split('-')
58 642f1bbd Stavros Sachtouris
        (rstart, rend) = (int(rstart), int(rend))
59 642f1bbd Stavros Sachtouris
        if rstart > end or rend < start:
60 3dabe5d2 Stavros Sachtouris
            return (0, 0)
61 642f1bbd Stavros Sachtouris
        if rstart > start:
62 642f1bbd Stavros Sachtouris
            start = rstart
63 642f1bbd Stavros Sachtouris
        if rend < end:
64 642f1bbd Stavros Sachtouris
            end = rend
65 642f1bbd Stavros Sachtouris
    return (start, end)
66 642f1bbd Stavros Sachtouris
67 3dabe5d2 Stavros Sachtouris
68 64ab4c13 Stavros Sachtouris
class PithosClient(PithosRestAPI):
69 d2cea1e2 Giorgos Verigakis
    """GRNet Pithos API client"""
70 a91e0293 Giorgos Verigakis
71 e02728f9 Stavros Sachtouris
    _thread_exceptions = []
72 e02728f9 Stavros Sachtouris
73 3dabe5d2 Stavros Sachtouris
    def __init__(self, base_url, token, account=None, container=None):
74 3dabe5d2 Stavros Sachtouris
        super(PithosClient, self).__init__(base_url, token, account, container)
75 435008b6 Stavros Sachtouris
76 2a7292f1 Stavros Sachtouris
    def purge_container(self, container=None):
77 4375e020 Stavros Sachtouris
        """Delete an empty container and destroy associated blocks
78 4375e020 Stavros Sachtouris
        """
79 2a7292f1 Stavros Sachtouris
        cnt_back_up = self.container
80 2a7292f1 Stavros Sachtouris
        try:
81 2a7292f1 Stavros Sachtouris
            self.container = container or cnt_back_up
82 2a7292f1 Stavros Sachtouris
            r = self.container_delete(until=unicode(time()))
83 2a7292f1 Stavros Sachtouris
        finally:
84 2a7292f1 Stavros Sachtouris
            self.container = cnt_back_up
85 6ce9fc72 Stavros Sachtouris
        r.release()
86 3dabe5d2 Stavros Sachtouris
87 24ff0a35 Stavros Sachtouris
    def upload_object_unchunked(
88 24ff0a35 Stavros Sachtouris
            self, obj, f,
89 24ff0a35 Stavros Sachtouris
            withHashFile=False,
90 24ff0a35 Stavros Sachtouris
            size=None,
91 24ff0a35 Stavros Sachtouris
            etag=None,
92 24ff0a35 Stavros Sachtouris
            content_encoding=None,
93 24ff0a35 Stavros Sachtouris
            content_disposition=None,
94 24ff0a35 Stavros Sachtouris
            content_type=None,
95 24ff0a35 Stavros Sachtouris
            sharing=None,
96 24ff0a35 Stavros Sachtouris
            public=None):
97 4375e020 Stavros Sachtouris
        """
98 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
99 4375e020 Stavros Sachtouris

100 4375e020 Stavros Sachtouris
        :param f: open file descriptor
101 4375e020 Stavros Sachtouris

102 4375e020 Stavros Sachtouris
        :param withHashFile: (bool)
103 4375e020 Stavros Sachtouris

104 4375e020 Stavros Sachtouris
        :param size: (int) size of data to upload
105 4375e020 Stavros Sachtouris

106 4375e020 Stavros Sachtouris
        :param etag: (str)
107 4375e020 Stavros Sachtouris

108 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
109 4375e020 Stavros Sachtouris

110 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
111 4375e020 Stavros Sachtouris

112 4375e020 Stavros Sachtouris
        :param content_type: (str)
113 4375e020 Stavros Sachtouris

114 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
115 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
116 4375e020 Stavros Sachtouris

117 4375e020 Stavros Sachtouris
        :param public: (bool)
118 4375e020 Stavros Sachtouris
        """
119 277ca4ed Dionysis Zindros
        self._assert_container()
120 65a45524 Stavros Sachtouris
121 65a45524 Stavros Sachtouris
        if withHashFile:
122 65a45524 Stavros Sachtouris
            data = f.read()
123 65a45524 Stavros Sachtouris
            try:
124 65a45524 Stavros Sachtouris
                import json
125 65a45524 Stavros Sachtouris
                data = json.dumps(json.loads(data))
126 65a45524 Stavros Sachtouris
            except ValueError:
127 24ff0a35 Stavros Sachtouris
                raise ClientError('"%s" is not json-formated' % f.name, 1)
128 65a45524 Stavros Sachtouris
            except SyntaxError:
129 24ff0a35 Stavros Sachtouris
                msg = '"%s" is not a valid hashmap file' % f.name
130 24ff0a35 Stavros Sachtouris
                raise ClientError(msg, 1)
131 65a45524 Stavros Sachtouris
            f = StringIO(data)
132 2a7292f1 Stavros Sachtouris
        else:
133 2a7292f1 Stavros Sachtouris
            data = f.read(size) if size is not None else f.read()
134 24ff0a35 Stavros Sachtouris
        r = self.object_put(
135 24ff0a35 Stavros Sachtouris
            obj,
136 3dabe5d2 Stavros Sachtouris
            data=data,
137 3dabe5d2 Stavros Sachtouris
            etag=etag,
138 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
139 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
140 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
141 3dabe5d2 Stavros Sachtouris
            permissions=sharing,
142 3dabe5d2 Stavros Sachtouris
            public=public,
143 3dabe5d2 Stavros Sachtouris
            success=201)
144 6ce9fc72 Stavros Sachtouris
        r.release()
145 3dabe5d2 Stavros Sachtouris
146 24ff0a35 Stavros Sachtouris
    def create_object_by_manifestation(
147 24ff0a35 Stavros Sachtouris
            self, obj,
148 24ff0a35 Stavros Sachtouris
            etag=None,
149 24ff0a35 Stavros Sachtouris
            content_encoding=None,
150 24ff0a35 Stavros Sachtouris
            content_disposition=None,
151 24ff0a35 Stavros Sachtouris
            content_type=None,
152 24ff0a35 Stavros Sachtouris
            sharing=None,
153 24ff0a35 Stavros Sachtouris
            public=None):
154 4375e020 Stavros Sachtouris
        """
155 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
156 4375e020 Stavros Sachtouris

157 4375e020 Stavros Sachtouris
        :param etag: (str)
158 4375e020 Stavros Sachtouris

159 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
160 4375e020 Stavros Sachtouris

161 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
162 4375e020 Stavros Sachtouris

163 4375e020 Stavros Sachtouris
        :param content_type: (str)
164 4375e020 Stavros Sachtouris

165 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
166 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
167 4375e020 Stavros Sachtouris

168 4375e020 Stavros Sachtouris
        :param public: (bool)
169 4375e020 Stavros Sachtouris
        """
170 277ca4ed Dionysis Zindros
        self._assert_container()
171 24ff0a35 Stavros Sachtouris
        r = self.object_put(
172 24ff0a35 Stavros Sachtouris
            obj,
173 3dabe5d2 Stavros Sachtouris
            content_length=0,
174 3dabe5d2 Stavros Sachtouris
            etag=etag,
175 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
176 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
177 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
178 3dabe5d2 Stavros Sachtouris
            permissions=sharing,
179 3dabe5d2 Stavros Sachtouris
            public=public,
180 3dabe5d2 Stavros Sachtouris
            manifest='%s/%s' % (self.container, obj))
181 6ce9fc72 Stavros Sachtouris
        r.release()
182 3dabe5d2 Stavros Sachtouris
183 4375e020 Stavros Sachtouris
    # upload_* auxiliary methods
184 1d329d27 Stavros Sachtouris
    def _put_block_async(self, data, hash, upload_gen=None):
185 4375e020 Stavros Sachtouris
        event = SilentEvent(method=self._put_block, data=data, hash=hash)
186 4375e020 Stavros Sachtouris
        event.start()
187 4375e020 Stavros Sachtouris
        return event
188 4375e020 Stavros Sachtouris
189 4375e020 Stavros Sachtouris
    def _put_block(self, data, hash):
190 24ff0a35 Stavros Sachtouris
        r = self.container_post(
191 24ff0a35 Stavros Sachtouris
            update=True,
192 4375e020 Stavros Sachtouris
            content_type='application/octet-stream',
193 4375e020 Stavros Sachtouris
            content_length=len(data),
194 4375e020 Stavros Sachtouris
            data=data,
195 4375e020 Stavros Sachtouris
            format='json')
196 4375e020 Stavros Sachtouris
        assert r.json[0] == hash, 'Local hash does not match server'
197 4375e020 Stavros Sachtouris
198 64ab4c13 Stavros Sachtouris
    def _get_file_block_info(self, fileobj, size=None):
199 2f749e6e Stavros Sachtouris
        meta = self.get_container_info()
200 435008b6 Stavros Sachtouris
        blocksize = int(meta['x-container-block-size'])
201 435008b6 Stavros Sachtouris
        blockhash = meta['x-container-block-hash']
202 64ab4c13 Stavros Sachtouris
        size = size if size is not None else fstat(fileobj.fileno()).st_size
203 435008b6 Stavros Sachtouris
        nblocks = 1 + (size - 1) // blocksize
204 64ab4c13 Stavros Sachtouris
        return (blocksize, blockhash, size, nblocks)
205 64ab4c13 Stavros Sachtouris
206 24ff0a35 Stavros Sachtouris
    def _get_missing_hashes(
207 24ff0a35 Stavros Sachtouris
            self, obj, json,
208 24ff0a35 Stavros Sachtouris
            size=None,
209 24ff0a35 Stavros Sachtouris
            format='json',
210 24ff0a35 Stavros Sachtouris
            hashmap=True,
211 24ff0a35 Stavros Sachtouris
            content_type=None,
212 24ff0a35 Stavros Sachtouris
            etag=None,
213 24ff0a35 Stavros Sachtouris
            content_encoding=None,
214 24ff0a35 Stavros Sachtouris
            content_disposition=None,
215 24ff0a35 Stavros Sachtouris
            permissions=None,
216 24ff0a35 Stavros Sachtouris
            public=None,
217 24ff0a35 Stavros Sachtouris
            success=(201, 409)):
218 24ff0a35 Stavros Sachtouris
        r = self.object_put(
219 24ff0a35 Stavros Sachtouris
            obj,
220 3dabe5d2 Stavros Sachtouris
            format='json',
221 3dabe5d2 Stavros Sachtouris
            hashmap=True,
222 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
223 3dabe5d2 Stavros Sachtouris
            json=json,
224 3dabe5d2 Stavros Sachtouris
            etag=etag,
225 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
226 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
227 3dabe5d2 Stavros Sachtouris
            permissions=permissions,
228 3dabe5d2 Stavros Sachtouris
            public=public,
229 64ab4c13 Stavros Sachtouris
            success=success)
230 64ab4c13 Stavros Sachtouris
        if r.status_code == 201:
231 6ce9fc72 Stavros Sachtouris
            r.release()
232 64ab4c13 Stavros Sachtouris
            return None
233 64ab4c13 Stavros Sachtouris
        return r.json
234 435008b6 Stavros Sachtouris
235 bcbf3cf0 Stavros Sachtouris
    def _culculate_blocks_for_upload(
236 2005b18e Stavros Sachtouris
            self, blocksize, blockhash, size, nblocks, hashes, hmap, fileobj,
237 2005b18e Stavros Sachtouris
            hash_cb=None):
238 3dabe5d2 Stavros Sachtouris
        offset = 0
239 435008b6 Stavros Sachtouris
        if hash_cb:
240 435008b6 Stavros Sachtouris
            hash_gen = hash_cb(nblocks)
241 435008b6 Stavros Sachtouris
            hash_gen.next()
242 435008b6 Stavros Sachtouris
243 435008b6 Stavros Sachtouris
        for i in range(nblocks):
244 64ab4c13 Stavros Sachtouris
            block = fileobj.read(min(blocksize, size - offset))
245 435008b6 Stavros Sachtouris
            bytes = len(block)
246 4375e020 Stavros Sachtouris
            hash = _pithos_hash(block, blockhash)
247 435008b6 Stavros Sachtouris
            hashes.append(hash)
248 5b263ba2 Stavros Sachtouris
            hmap[hash] = (offset, bytes)
249 435008b6 Stavros Sachtouris
            offset += bytes
250 435008b6 Stavros Sachtouris
            if hash_cb:
251 435008b6 Stavros Sachtouris
                hash_gen.next()
252 fce31e83 Stavros Sachtouris
        msg = 'Failed to calculate uploaded blocks:'
253 bcbf3cf0 Stavros Sachtouris
        ' Offset and object size do not match'
254 fce31e83 Stavros Sachtouris
        assert offset == size, msg
255 435008b6 Stavros Sachtouris
256 3e7d1e0e Stavros Sachtouris
    def _upload_missing_blocks(self, missing, hmap, fileobj, upload_gen=None):
257 3e7d1e0e Stavros Sachtouris
        """upload missing blocks asynchronously"""
258 435008b6 Stavros Sachtouris
259 cad39033 Stavros Sachtouris
        self._init_thread_limit()
260 e9abe82b Stavros Sachtouris
261 435008b6 Stavros Sachtouris
        flying = []
262 7644c38e Stavros Sachtouris
        failures = []
263 435008b6 Stavros Sachtouris
        for hash in missing:
264 5b263ba2 Stavros Sachtouris
            offset, bytes = hmap[hash]
265 64ab4c13 Stavros Sachtouris
            fileobj.seek(offset)
266 64ab4c13 Stavros Sachtouris
            data = fileobj.read(bytes)
267 1d329d27 Stavros Sachtouris
            r = self._put_block_async(data, hash, upload_gen)
268 435008b6 Stavros Sachtouris
            flying.append(r)
269 745d938b Stavros Sachtouris
            unfinished = self._watch_thread_limit(flying)
270 745d938b Stavros Sachtouris
            for thread in set(flying).difference(unfinished):
271 7644c38e Stavros Sachtouris
                if thread.exception:
272 7644c38e Stavros Sachtouris
                    failures.append(thread)
273 24ff0a35 Stavros Sachtouris
                    if isinstance(
274 2005b18e Stavros Sachtouris
                            thread.exception,
275 2005b18e Stavros Sachtouris
                            ClientError) and thread.exception.status == 502:
276 2005b18e Stavros Sachtouris
                        self.POOLSIZE = self._thread_limit
277 7644c38e Stavros Sachtouris
                elif thread.isAlive():
278 745d938b Stavros Sachtouris
                    flying.append(thread)
279 3e7d1e0e Stavros Sachtouris
                elif upload_gen:
280 3e7d1e0e Stavros Sachtouris
                    try:
281 3e7d1e0e Stavros Sachtouris
                        upload_gen.next()
282 3e7d1e0e Stavros Sachtouris
                    except:
283 3e7d1e0e Stavros Sachtouris
                        pass
284 e02728f9 Stavros Sachtouris
            flying = unfinished
285 e02728f9 Stavros Sachtouris
286 e02728f9 Stavros Sachtouris
        for thread in flying:
287 e02728f9 Stavros Sachtouris
            thread.join()
288 7644c38e Stavros Sachtouris
            if thread.exception:
289 7644c38e Stavros Sachtouris
                failures.append(thread)
290 3e7d1e0e Stavros Sachtouris
            elif upload_gen:
291 3e7d1e0e Stavros Sachtouris
                try:
292 3e7d1e0e Stavros Sachtouris
                    upload_gen.next()
293 3e7d1e0e Stavros Sachtouris
                except:
294 3e7d1e0e Stavros Sachtouris
                    pass
295 56f0908a Stavros Sachtouris
296 7644c38e Stavros Sachtouris
        return [failure.kwargs['hash'] for failure in failures]
297 3dabe5d2 Stavros Sachtouris
298 24ff0a35 Stavros Sachtouris
    def upload_object(
299 24ff0a35 Stavros Sachtouris
            self, obj, f,
300 24ff0a35 Stavros Sachtouris
            size=None,
301 24ff0a35 Stavros Sachtouris
            hash_cb=None,
302 24ff0a35 Stavros Sachtouris
            upload_cb=None,
303 24ff0a35 Stavros Sachtouris
            etag=None,
304 24ff0a35 Stavros Sachtouris
            content_encoding=None,
305 24ff0a35 Stavros Sachtouris
            content_disposition=None,
306 24ff0a35 Stavros Sachtouris
            content_type=None,
307 24ff0a35 Stavros Sachtouris
            sharing=None,
308 24ff0a35 Stavros Sachtouris
            public=None):
309 4375e020 Stavros Sachtouris
        """Upload an object using multiple connections (threads)
310 4375e020 Stavros Sachtouris

311 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
312 4375e020 Stavros Sachtouris

313 4375e020 Stavros Sachtouris
        :param f: open file descriptor (rb)
314 4375e020 Stavros Sachtouris

315 4375e020 Stavros Sachtouris
        :param hash_cb: optional progress.bar object for calculating hashes
316 4375e020 Stavros Sachtouris

317 4375e020 Stavros Sachtouris
        :param upload_cb: optional progress.bar object for uploading
318 4375e020 Stavros Sachtouris

319 4375e020 Stavros Sachtouris
        :param etag: (str)
320 4375e020 Stavros Sachtouris

321 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
322 4375e020 Stavros Sachtouris

323 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
324 4375e020 Stavros Sachtouris

325 4375e020 Stavros Sachtouris
        :param content_type: (str)
326 4375e020 Stavros Sachtouris

327 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
328 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
329 4375e020 Stavros Sachtouris

330 4375e020 Stavros Sachtouris
        :param public: (bool)
331 4375e020 Stavros Sachtouris
        """
332 277ca4ed Dionysis Zindros
        self._assert_container()
333 56f0908a Stavros Sachtouris
334 64ab4c13 Stavros Sachtouris
        #init
335 3dabe5d2 Stavros Sachtouris
        block_info = (blocksize, blockhash, size, nblocks) =\
336 3dabe5d2 Stavros Sachtouris
            self._get_file_block_info(f, size)
337 64ab4c13 Stavros Sachtouris
        (hashes, hmap, offset) = ([], {}, 0)
338 bcbf3cf0 Stavros Sachtouris
        if not content_type:
339 3dabe5d2 Stavros Sachtouris
            content_type = 'application/octet-stream'
340 64ab4c13 Stavros Sachtouris
341 bcbf3cf0 Stavros Sachtouris
        self._culculate_blocks_for_upload(
342 24ff0a35 Stavros Sachtouris
            *block_info,
343 3dabe5d2 Stavros Sachtouris
            hashes=hashes,
344 3dabe5d2 Stavros Sachtouris
            hmap=hmap,
345 3dabe5d2 Stavros Sachtouris
            fileobj=f,
346 64ab4c13 Stavros Sachtouris
            hash_cb=hash_cb)
347 64ab4c13 Stavros Sachtouris
348 64ab4c13 Stavros Sachtouris
        hashmap = dict(bytes=size, hashes=hashes)
349 24ff0a35 Stavros Sachtouris
        missing = self._get_missing_hashes(
350 24ff0a35 Stavros Sachtouris
            obj, hashmap,
351 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
352 3dabe5d2 Stavros Sachtouris
            size=size,
353 3dabe5d2 Stavros Sachtouris
            etag=etag,
354 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
355 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
356 3dabe5d2 Stavros Sachtouris
            permissions=sharing,
357 3dabe5d2 Stavros Sachtouris
            public=public)
358 64ab4c13 Stavros Sachtouris
359 64ab4c13 Stavros Sachtouris
        if missing is None:
360 64ab4c13 Stavros Sachtouris
            return
361 1d329d27 Stavros Sachtouris
362 3e7d1e0e Stavros Sachtouris
        if upload_cb:
363 3e7d1e0e Stavros Sachtouris
            upload_gen = upload_cb(len(missing))
364 745d938b Stavros Sachtouris
            for i in range(len(missing), len(hashmap['hashes']) + 1):
365 745d938b Stavros Sachtouris
                try:
366 745d938b Stavros Sachtouris
                    upload_gen.next()
367 745d938b Stavros Sachtouris
                except:
368 745d938b Stavros Sachtouris
                    upload_gen = None
369 3e7d1e0e Stavros Sachtouris
        else:
370 3e7d1e0e Stavros Sachtouris
            upload_gen = None
371 3e7d1e0e Stavros Sachtouris
372 7eda693f Stavros Sachtouris
        retries = 7
373 f27ed9a0 Stavros Sachtouris
        try:
374 7644c38e Stavros Sachtouris
            while retries:
375 7eda693f Stavros Sachtouris
                sendlog.info('%s blocks missing' % len(missing))
376 7644c38e Stavros Sachtouris
                num_of_blocks = len(missing)
377 7644c38e Stavros Sachtouris
                missing = self._upload_missing_blocks(
378 7644c38e Stavros Sachtouris
                    missing,
379 7644c38e Stavros Sachtouris
                    hmap,
380 7644c38e Stavros Sachtouris
                    f,
381 3e7d1e0e Stavros Sachtouris
                    upload_gen)
382 16c895db Stavros Sachtouris
                if missing:
383 16c895db Stavros Sachtouris
                    if num_of_blocks == len(missing):
384 16c895db Stavros Sachtouris
                        retries -= 1
385 16c895db Stavros Sachtouris
                    else:
386 16c895db Stavros Sachtouris
                        num_of_blocks = len(missing)
387 7644c38e Stavros Sachtouris
                else:
388 7644c38e Stavros Sachtouris
                    break
389 7644c38e Stavros Sachtouris
            if missing:
390 7644c38e Stavros Sachtouris
                raise ClientError(
391 7644c38e Stavros Sachtouris
                    '%s blocks failed to upload' % len(missing),
392 7644c38e Stavros Sachtouris
                    status=800)
393 f27ed9a0 Stavros Sachtouris
        except KeyboardInterrupt:
394 6069b53b Stavros Sachtouris
            sendlog.info('- - - wait for threads to finish')
395 f27ed9a0 Stavros Sachtouris
            for thread in activethreads():
396 f27ed9a0 Stavros Sachtouris
                thread.join()
397 f27ed9a0 Stavros Sachtouris
            raise
398 f27ed9a0 Stavros Sachtouris
399 f27ed9a0 Stavros Sachtouris
        r = self.object_put(
400 f27ed9a0 Stavros Sachtouris
            obj,
401 3dabe5d2 Stavros Sachtouris
            format='json',
402 3dabe5d2 Stavros Sachtouris
            hashmap=True,
403 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
404 3dabe5d2 Stavros Sachtouris
            json=hashmap,
405 3dabe5d2 Stavros Sachtouris
            success=201)
406 6ce9fc72 Stavros Sachtouris
        r.release()
407 3dabe5d2 Stavros Sachtouris
408 f27ed9a0 Stavros Sachtouris
    # download_* auxiliary methods
409 fbfee225 Stavros Sachtouris
    def _get_remote_blocks_info(self, obj, **restargs):
410 56f0908a Stavros Sachtouris
        #retrieve object hashmap
411 3dabe5d2 Stavros Sachtouris
        myrange = restargs.pop('data_range', None)
412 319be41b Stavros Sachtouris
        hashmap = self.get_object_hashmap(obj, **restargs)
413 642f1bbd Stavros Sachtouris
        restargs['data_range'] = myrange
414 56f0908a Stavros Sachtouris
        blocksize = int(hashmap['block_size'])
415 56f0908a Stavros Sachtouris
        blockhash = hashmap['block_hash']
416 56f0908a Stavros Sachtouris
        total_size = hashmap['bytes']
417 fbfee225 Stavros Sachtouris
        #assert total_size/blocksize + 1 == len(hashmap['hashes'])
418 56f0908a Stavros Sachtouris
        map_dict = {}
419 fbfee225 Stavros Sachtouris
        for i, h in enumerate(hashmap['hashes']):
420 fbfee225 Stavros Sachtouris
            map_dict[h] = i
421 fbfee225 Stavros Sachtouris
        return (blocksize, blockhash, total_size, hashmap['hashes'], map_dict)
422 64ab4c13 Stavros Sachtouris
423 24ff0a35 Stavros Sachtouris
    def _dump_blocks_sync(
424 24ff0a35 Stavros Sachtouris
            self, obj, remote_hashes, blocksize, total_size, dst, range,
425 24ff0a35 Stavros Sachtouris
            **args):
426 fbfee225 Stavros Sachtouris
        for blockid, blockhash in enumerate(remote_hashes):
427 24ff0a35 Stavros Sachtouris
            if blockhash:
428 24ff0a35 Stavros Sachtouris
                start = blocksize * blockid
429 24ff0a35 Stavros Sachtouris
                is_last = start + blocksize > total_size
430 24ff0a35 Stavros Sachtouris
                end = (total_size - 1) if is_last else (start + blocksize - 1)
431 24ff0a35 Stavros Sachtouris
                (start, end) = _range_up(start, end, range)
432 24ff0a35 Stavros Sachtouris
                args['data_range'] = 'bytes=%s-%s' % (start, end)
433 24ff0a35 Stavros Sachtouris
                r = self.object_get(obj, success=(200, 206), **args)
434 24ff0a35 Stavros Sachtouris
                self._cb_next()
435 24ff0a35 Stavros Sachtouris
                dst.write(r.content)
436 24ff0a35 Stavros Sachtouris
                dst.flush()
437 fbfee225 Stavros Sachtouris
438 24ff0a35 Stavros Sachtouris
    def _get_block_async(self, obj, **args):
439 24ff0a35 Stavros Sachtouris
        event = SilentEvent(self.object_get, obj, success=(200, 206), **args)
440 e02728f9 Stavros Sachtouris
        event.start()
441 e02728f9 Stavros Sachtouris
        return event
442 fb0cd49a Stavros Sachtouris
443 48c3782c Stavros Sachtouris
    def _hash_from_file(self, fp, start, size, blockhash):
444 48c3782c Stavros Sachtouris
        fp.seek(start)
445 48c3782c Stavros Sachtouris
        block = fp.read(size)
446 48c3782c Stavros Sachtouris
        h = newhashlib(blockhash)
447 48c3782c Stavros Sachtouris
        h.update(block.strip('\x00'))
448 48c3782c Stavros Sachtouris
        return hexlify(h.digest())
449 48c3782c Stavros Sachtouris
450 24ff0a35 Stavros Sachtouris
    def _thread2file(self, flying, local_file, offset=0, **restargs):
451 22fc09fb Stavros Sachtouris
        """write the results of a greenleted rest call to a file
452 f5f2dc53 Stavros Sachtouris

453 f5f2dc53 Stavros Sachtouris
        :param offset: the offset of the file up to blocksize
454 f5f2dc53 Stavros Sachtouris
        - e.g. if the range is 10-100, all blocks will be written to
455 f5f2dc53 Stavros Sachtouris
        normal_position - 10
456 f5f2dc53 Stavros Sachtouris
        """
457 fbfee225 Stavros Sachtouris
        finished = []
458 f27ed9a0 Stavros Sachtouris
        for i, (start, g) in enumerate(flying.items()):
459 e02728f9 Stavros Sachtouris
            if not g.isAlive():
460 fbfee225 Stavros Sachtouris
                if g.exception:
461 fbfee225 Stavros Sachtouris
                    raise g.exception
462 1785ad41 Stavros Sachtouris
                block = g.value.content
463 22fc09fb Stavros Sachtouris
                local_file.seek(start - offset)
464 fbfee225 Stavros Sachtouris
                local_file.write(block)
465 fbfee225 Stavros Sachtouris
                self._cb_next()
466 e02728f9 Stavros Sachtouris
                finished.append(flying.pop(start))
467 fbfee225 Stavros Sachtouris
        local_file.flush()
468 fbfee225 Stavros Sachtouris
        return finished
469 fbfee225 Stavros Sachtouris
470 24ff0a35 Stavros Sachtouris
    def _dump_blocks_async(
471 24ff0a35 Stavros Sachtouris
            self, obj, remote_hashes, blocksize, total_size, local_file,
472 24ff0a35 Stavros Sachtouris
            blockhash=None, resume=False, filerange=None, **restargs):
473 973fbcad Stavros Sachtouris
        file_size = fstat(local_file.fileno()).st_size if resume else 0
474 e02728f9 Stavros Sachtouris
        flying = {}
475 e02728f9 Stavros Sachtouris
        finished = []
476 22fc09fb Stavros Sachtouris
        offset = 0
477 22fc09fb Stavros Sachtouris
        if filerange is not None:
478 22fc09fb Stavros Sachtouris
            rstart = int(filerange.split('-')[0])
479 3dabe5d2 Stavros Sachtouris
            offset = rstart if blocksize > rstart else rstart % blocksize
480 f27ed9a0 Stavros Sachtouris
481 cad39033 Stavros Sachtouris
        self._init_thread_limit()
482 fbfee225 Stavros Sachtouris
        for block_hash, blockid in remote_hashes.items():
483 3dabe5d2 Stavros Sachtouris
            start = blocksize * blockid
484 24ff0a35 Stavros Sachtouris
            if start < file_size and block_hash == self._hash_from_file(
485 24ff0a35 Stavros Sachtouris
                    local_file, start, blocksize, blockhash):
486 3dabe5d2 Stavros Sachtouris
                self._cb_next()
487 3dabe5d2 Stavros Sachtouris
                continue
488 cad39033 Stavros Sachtouris
            self._watch_thread_limit(flying.values())
489 f27ed9a0 Stavros Sachtouris
            finished += self._thread2file(
490 f27ed9a0 Stavros Sachtouris
                flying,
491 f27ed9a0 Stavros Sachtouris
                local_file,
492 f27ed9a0 Stavros Sachtouris
                offset,
493 f27ed9a0 Stavros Sachtouris
                **restargs)
494 3dabe5d2 Stavros Sachtouris
            end = total_size - 1 if start + blocksize > total_size\
495 3dabe5d2 Stavros Sachtouris
                else start + blocksize - 1
496 22fc09fb Stavros Sachtouris
            (start, end) = _range_up(start, end, filerange)
497 22fc09fb Stavros Sachtouris
            if start == end:
498 22fc09fb Stavros Sachtouris
                self._cb_next()
499 22fc09fb Stavros Sachtouris
                continue
500 3dabe5d2 Stavros Sachtouris
            restargs['async_headers'] = {'Range': 'bytes=%s-%s' % (start, end)}
501 e02728f9 Stavros Sachtouris
            flying[start] = self._get_block_async(obj, **restargs)
502 fbfee225 Stavros Sachtouris
503 e02728f9 Stavros Sachtouris
        for thread in flying.values():
504 e02728f9 Stavros Sachtouris
            thread.join()
505 e02728f9 Stavros Sachtouris
        finished += self._thread2file(flying, local_file, offset, **restargs)
506 fbfee225 Stavros Sachtouris
507 24ff0a35 Stavros Sachtouris
    def download_object(
508 24ff0a35 Stavros Sachtouris
            self, obj, dst,
509 24ff0a35 Stavros Sachtouris
            download_cb=None,
510 24ff0a35 Stavros Sachtouris
            version=None,
511 24ff0a35 Stavros Sachtouris
            resume=False,
512 24ff0a35 Stavros Sachtouris
            range_str=None,
513 24ff0a35 Stavros Sachtouris
            if_match=None,
514 24ff0a35 Stavros Sachtouris
            if_none_match=None,
515 24ff0a35 Stavros Sachtouris
            if_modified_since=None,
516 24ff0a35 Stavros Sachtouris
            if_unmodified_since=None):
517 f5f2dc53 Stavros Sachtouris
        """Download an object (multiple connections, random blocks)
518 4375e020 Stavros Sachtouris

519 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
520 4375e020 Stavros Sachtouris

521 4375e020 Stavros Sachtouris
        :param dst: open file descriptor (wb+)
522 4375e020 Stavros Sachtouris

523 4375e020 Stavros Sachtouris
        :param download_cb: optional progress.bar object for downloading
524 4375e020 Stavros Sachtouris

525 4375e020 Stavros Sachtouris
        :param version: (str) file version
526 4375e020 Stavros Sachtouris

527 4375e020 Stavros Sachtouris
        :param resume: (bool) if set, preserve already downloaded file parts
528 4375e020 Stavros Sachtouris

529 f5f2dc53 Stavros Sachtouris
        :param range_str: (str) from, to are file positions (int) in bytes
530 4375e020 Stavros Sachtouris

531 4375e020 Stavros Sachtouris
        :param if_match: (str)
532 4375e020 Stavros Sachtouris

533 4375e020 Stavros Sachtouris
        :param if_none_match: (str)
534 4375e020 Stavros Sachtouris

535 4375e020 Stavros Sachtouris
        :param if_modified_since: (str) formated date
536 4375e020 Stavros Sachtouris

537 f5f2dc53 Stavros Sachtouris
        :param if_unmodified_since: (str) formated date"""
538 24ff0a35 Stavros Sachtouris
        restargs = dict(
539 24ff0a35 Stavros Sachtouris
            version=version,
540 24ff0a35 Stavros Sachtouris
            data_range=None if range_str is None else 'bytes=%s' % range_str,
541 fbfee225 Stavros Sachtouris
            if_match=if_match,
542 fbfee225 Stavros Sachtouris
            if_none_match=if_none_match,
543 fbfee225 Stavros Sachtouris
            if_modified_since=if_modified_since,
544 fbfee225 Stavros Sachtouris
            if_unmodified_since=if_unmodified_since)
545 fbfee225 Stavros Sachtouris
546 24ff0a35 Stavros Sachtouris
        (
547 24ff0a35 Stavros Sachtouris
            blocksize,
548 fbfee225 Stavros Sachtouris
            blockhash,
549 fbfee225 Stavros Sachtouris
            total_size,
550 3dabe5d2 Stavros Sachtouris
            hash_list,
551 fbfee225 Stavros Sachtouris
            remote_hashes) = self._get_remote_blocks_info(obj, **restargs)
552 fbfee225 Stavros Sachtouris
        assert total_size >= 0
553 fbfee225 Stavros Sachtouris
554 fbfee225 Stavros Sachtouris
        if download_cb:
555 20c13fcc Stavros Sachtouris
            self.progress_bar_gen = download_cb(len(remote_hashes))
556 fbfee225 Stavros Sachtouris
            self._cb_next()
557 fbfee225 Stavros Sachtouris
558 fbfee225 Stavros Sachtouris
        if dst.isatty():
559 24ff0a35 Stavros Sachtouris
            self._dump_blocks_sync(
560 24ff0a35 Stavros Sachtouris
                obj,
561 3dabe5d2 Stavros Sachtouris
                hash_list,
562 3dabe5d2 Stavros Sachtouris
                blocksize,
563 3dabe5d2 Stavros Sachtouris
                total_size,
564 3dabe5d2 Stavros Sachtouris
                dst,
565 24ff0a35 Stavros Sachtouris
                range_str,
566 3dabe5d2 Stavros Sachtouris
                **restargs)
567 699d3bb1 Stavros Sachtouris
        else:
568 24ff0a35 Stavros Sachtouris
            self._dump_blocks_async(
569 24ff0a35 Stavros Sachtouris
                obj,
570 3dabe5d2 Stavros Sachtouris
                remote_hashes,
571 3dabe5d2 Stavros Sachtouris
                blocksize,
572 3dabe5d2 Stavros Sachtouris
                total_size,
573 3dabe5d2 Stavros Sachtouris
                dst,
574 3dabe5d2 Stavros Sachtouris
                blockhash,
575 3dabe5d2 Stavros Sachtouris
                resume,
576 24ff0a35 Stavros Sachtouris
                range_str,
577 3dabe5d2 Stavros Sachtouris
                **restargs)
578 24ff0a35 Stavros Sachtouris
            if not range_str:
579 22fc09fb Stavros Sachtouris
                dst.truncate(total_size)
580 5b263ba2 Stavros Sachtouris
581 fbfee225 Stavros Sachtouris
        self._complete_cb()
582 fbfee225 Stavros Sachtouris
583 fbfee225 Stavros Sachtouris
    #Command Progress Bar method
584 fbfee225 Stavros Sachtouris
    def _cb_next(self):
585 fbfee225 Stavros Sachtouris
        if hasattr(self, 'progress_bar_gen'):
586 fbfee225 Stavros Sachtouris
            try:
587 fbfee225 Stavros Sachtouris
                self.progress_bar_gen.next()
588 fbfee225 Stavros Sachtouris
            except:
589 fbfee225 Stavros Sachtouris
                pass
590 3dabe5d2 Stavros Sachtouris
591 fbfee225 Stavros Sachtouris
    def _complete_cb(self):
592 fbfee225 Stavros Sachtouris
        while True:
593 fbfee225 Stavros Sachtouris
            try:
594 fbfee225 Stavros Sachtouris
                self.progress_bar_gen.next()
595 fbfee225 Stavros Sachtouris
            except:
596 fbfee225 Stavros Sachtouris
                break
597 b1713259 Stavros Sachtouris
598 24ff0a35 Stavros Sachtouris
    def get_object_hashmap(
599 24ff0a35 Stavros Sachtouris
            self, obj,
600 24ff0a35 Stavros Sachtouris
            version=None,
601 24ff0a35 Stavros Sachtouris
            if_match=None,
602 24ff0a35 Stavros Sachtouris
            if_none_match=None,
603 24ff0a35 Stavros Sachtouris
            if_modified_since=None,
604 24ff0a35 Stavros Sachtouris
            if_unmodified_since=None,
605 24ff0a35 Stavros Sachtouris
            data_range=None):
606 4375e020 Stavros Sachtouris
        """
607 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
608 4375e020 Stavros Sachtouris

609 4375e020 Stavros Sachtouris
        :param if_match: (str)
610 4375e020 Stavros Sachtouris

611 4375e020 Stavros Sachtouris
        :param if_none_match: (str)
612 4375e020 Stavros Sachtouris

613 4375e020 Stavros Sachtouris
        :param if_modified_since: (str) formated date
614 4375e020 Stavros Sachtouris

615 4375e020 Stavros Sachtouris
        :param if_unmodified_since: (str) formated date
616 4375e020 Stavros Sachtouris

617 4375e020 Stavros Sachtouris
        :param data_range: (str) from-to where from and to are integers
618 4375e020 Stavros Sachtouris
            denoting file positions in bytes
619 4375e020 Stavros Sachtouris

620 4375e020 Stavros Sachtouris
        :returns: (list)
621 4375e020 Stavros Sachtouris
        """
622 d804de82 Stavros Sachtouris
        try:
623 24ff0a35 Stavros Sachtouris
            r = self.object_get(
624 24ff0a35 Stavros Sachtouris
                obj,
625 3dabe5d2 Stavros Sachtouris
                hashmap=True,
626 3dabe5d2 Stavros Sachtouris
                version=version,
627 3dabe5d2 Stavros Sachtouris
                if_etag_match=if_match,
628 3dabe5d2 Stavros Sachtouris
                if_etag_not_match=if_none_match,
629 3dabe5d2 Stavros Sachtouris
                if_modified_since=if_modified_since,
630 3dabe5d2 Stavros Sachtouris
                if_unmodified_since=if_unmodified_since,
631 3dabe5d2 Stavros Sachtouris
                data_range=data_range)
632 d804de82 Stavros Sachtouris
        except ClientError as err:
633 d804de82 Stavros Sachtouris
            if err.status == 304 or err.status == 412:
634 d804de82 Stavros Sachtouris
                return {}
635 d804de82 Stavros Sachtouris
            raise
636 64ab4c13 Stavros Sachtouris
        return r.json
637 56f0908a Stavros Sachtouris
638 3a9e54b0 Stavros Sachtouris
    def set_account_group(self, group, usernames):
639 4375e020 Stavros Sachtouris
        """
640 4375e020 Stavros Sachtouris
        :param group: (str)
641 4375e020 Stavros Sachtouris

642 4375e020 Stavros Sachtouris
        :param usernames: (list)
643 4375e020 Stavros Sachtouris
        """
644 3dabe5d2 Stavros Sachtouris
        r = self.account_post(update=True, groups={group: usernames})
645 6ce9fc72 Stavros Sachtouris
        r.release()
646 eb903ba7 Stavros Sachtouris
647 c2867610 Stavros Sachtouris
    def del_account_group(self, group):
648 4375e020 Stavros Sachtouris
        """
649 4375e020 Stavros Sachtouris
        :param group: (str)
650 4375e020 Stavros Sachtouris
        """
651 3dabe5d2 Stavros Sachtouris
        r = self.account_post(update=True, groups={group: []})
652 6ce9fc72 Stavros Sachtouris
        r.release()
653 c2867610 Stavros Sachtouris
654 8af4cc0b Stavros Sachtouris
    def get_account_info(self, until=None):
655 4375e020 Stavros Sachtouris
        """
656 4375e020 Stavros Sachtouris
        :param until: (str) formated date
657 4375e020 Stavros Sachtouris

658 4375e020 Stavros Sachtouris
        :returns: (dict)
659 4375e020 Stavros Sachtouris
        """
660 8af4cc0b Stavros Sachtouris
        r = self.account_head(until=until)
661 6657ec8c Stavros Sachtouris
        if r.status_code == 401:
662 24851aa5 Stavros Sachtouris
            raise ClientError("No authorization", status=401)
663 64ab4c13 Stavros Sachtouris
        return r.headers
664 6657ec8c Stavros Sachtouris
665 d1856abf Stavros Sachtouris
    def get_account_quota(self):
666 4375e020 Stavros Sachtouris
        """
667 4375e020 Stavros Sachtouris
        :returns: (dict)
668 4375e020 Stavros Sachtouris
        """
669 24ff0a35 Stavros Sachtouris
        return filter_in(
670 24ff0a35 Stavros Sachtouris
            self.get_account_info(),
671 3dabe5d2 Stavros Sachtouris
            'X-Account-Policy-Quota',
672 3dabe5d2 Stavros Sachtouris
            exactMatch=True)
673 d1856abf Stavros Sachtouris
674 d1856abf Stavros Sachtouris
    def get_account_versioning(self):
675 4375e020 Stavros Sachtouris
        """
676 4375e020 Stavros Sachtouris
        :returns: (dict)
677 4375e020 Stavros Sachtouris
        """
678 24ff0a35 Stavros Sachtouris
        return filter_in(
679 24ff0a35 Stavros Sachtouris
            self.get_account_info(),
680 3dabe5d2 Stavros Sachtouris
            'X-Account-Policy-Versioning',
681 3dabe5d2 Stavros Sachtouris
            exactMatch=True)
682 e6b39366 Stavros Sachtouris
683 8af4cc0b Stavros Sachtouris
    def get_account_meta(self, until=None):
684 4375e020 Stavros Sachtouris
        """
685 4375e020 Stavros Sachtouris
        :meta until: (str) formated date
686 4375e020 Stavros Sachtouris

687 4375e020 Stavros Sachtouris
        :returns: (dict)
688 4375e020 Stavros Sachtouris
        """
689 3dabe5d2 Stavros Sachtouris
        return filter_in(self.get_account_info(until=until), 'X-Account-Meta-')
690 af3b2b36 Stavros Sachtouris
691 c2867610 Stavros Sachtouris
    def get_account_group(self):
692 4375e020 Stavros Sachtouris
        """
693 4375e020 Stavros Sachtouris
        :returns: (dict)
694 4375e020 Stavros Sachtouris
        """
695 c2867610 Stavros Sachtouris
        return filter_in(self.get_account_info(), 'X-Account-Group-')
696 c2867610 Stavros Sachtouris
697 af3b2b36 Stavros Sachtouris
    def set_account_meta(self, metapairs):
698 4375e020 Stavros Sachtouris
        """
699 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
700 4375e020 Stavros Sachtouris
        """
701 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
702 6ce9fc72 Stavros Sachtouris
        r = self.account_post(update=True, metadata=metapairs)
703 6ce9fc72 Stavros Sachtouris
        r.release()
704 af3b2b36 Stavros Sachtouris
705 379cd4bb Stavros Sachtouris
    def del_account_meta(self, metakey):
706 4375e020 Stavros Sachtouris
        """
707 4375e020 Stavros Sachtouris
        :param metakey: (str) metadatum key
708 4375e020 Stavros Sachtouris
        """
709 3dabe5d2 Stavros Sachtouris
        r = self.account_post(update=True, metadata={metakey: ''})
710 6ce9fc72 Stavros Sachtouris
        r.release()
711 379cd4bb Stavros Sachtouris
712 d1856abf Stavros Sachtouris
    def set_account_quota(self, quota):
713 4375e020 Stavros Sachtouris
        """
714 4375e020 Stavros Sachtouris
        :param quota: (int)
715 4375e020 Stavros Sachtouris
        """
716 6ce9fc72 Stavros Sachtouris
        r = self.account_post(update=True, quota=quota)
717 6ce9fc72 Stavros Sachtouris
        r.release()
718 d1856abf Stavros Sachtouris
719 d1856abf Stavros Sachtouris
    def set_account_versioning(self, versioning):
720 4375e020 Stavros Sachtouris
        """
721 4375e020 Stavros Sachtouris
        "param versioning: (str)
722 4375e020 Stavros Sachtouris
        """
723 3dabe5d2 Stavros Sachtouris
        r = self.account_post(update=True, versioning=versioning)
724 6ce9fc72 Stavros Sachtouris
        r.release()
725 d1856abf Stavros Sachtouris
726 4fd88feb Stavros Sachtouris
    def list_containers(self):
727 4375e020 Stavros Sachtouris
        """
728 4375e020 Stavros Sachtouris
        :returns: (dict)
729 4375e020 Stavros Sachtouris
        """
730 4fd88feb Stavros Sachtouris
        r = self.account_get()
731 64ab4c13 Stavros Sachtouris
        return r.json
732 b758e547 Stavros Sachtouris
733 a298f2ab Stavros Sachtouris
    def del_container(self, until=None, delimiter=None):
734 4375e020 Stavros Sachtouris
        """
735 4375e020 Stavros Sachtouris
        :param until: (str) formated date
736 4375e020 Stavros Sachtouris

737 4c1882ab Stavros Sachtouris
        :param delimiter: (str) with / empty container
738 4375e020 Stavros Sachtouris

739 4375e020 Stavros Sachtouris
        :raises ClientError: 404 Container does not exist
740 4375e020 Stavros Sachtouris

741 4375e020 Stavros Sachtouris
        :raises ClientError: 409 Container is not empty
742 4375e020 Stavros Sachtouris
        """
743 277ca4ed Dionysis Zindros
        self._assert_container()
744 2005b18e Stavros Sachtouris
        r = self.container_delete(
745 2005b18e Stavros Sachtouris
            until=until,
746 3dabe5d2 Stavros Sachtouris
            delimiter=delimiter,
747 3dabe5d2 Stavros Sachtouris
            success=(204, 404, 409))
748 6ce9fc72 Stavros Sachtouris
        r.release()
749 a298f2ab Stavros Sachtouris
        if r.status_code == 404:
750 24ff0a35 Stavros Sachtouris
            raise ClientError(
751 24ff0a35 Stavros Sachtouris
                'Container "%s" does not exist' % self.container,
752 3dabe5d2 Stavros Sachtouris
                r.status_code)
753 a298f2ab Stavros Sachtouris
        elif r.status_code == 409:
754 24ff0a35 Stavros Sachtouris
            raise ClientError(
755 24ff0a35 Stavros Sachtouris
                'Container "%s" is not empty' % self.container,
756 3dabe5d2 Stavros Sachtouris
                r.status_code)
757 a298f2ab Stavros Sachtouris
758 bae347d3 Stavros Sachtouris
    def get_container_versioning(self, container=None):
759 4375e020 Stavros Sachtouris
        """
760 4375e020 Stavros Sachtouris
        :param container: (str)
761 4375e020 Stavros Sachtouris

762 4375e020 Stavros Sachtouris
        :returns: (dict)
763 4375e020 Stavros Sachtouris
        """
764 bae347d3 Stavros Sachtouris
        cnt_back_up = self.container
765 bae347d3 Stavros Sachtouris
        try:
766 bae347d3 Stavros Sachtouris
            self.container = container or cnt_back_up
767 bae347d3 Stavros Sachtouris
            return filter_in(
768 bae347d3 Stavros Sachtouris
                self.get_container_info(),
769 bae347d3 Stavros Sachtouris
                'X-Container-Policy-Versioning')
770 bae347d3 Stavros Sachtouris
        finally:
771 bae347d3 Stavros Sachtouris
            self.container = cnt_back_up
772 d1856abf Stavros Sachtouris
773 1879e310 Stavros Sachtouris
    def get_container_quota(self, container=None):
774 4375e020 Stavros Sachtouris
        """
775 4375e020 Stavros Sachtouris
        :param container: (str)
776 4375e020 Stavros Sachtouris

777 4375e020 Stavros Sachtouris
        :returns: (dict)
778 4375e020 Stavros Sachtouris
        """
779 1879e310 Stavros Sachtouris
        cnt_back_up = self.container
780 1879e310 Stavros Sachtouris
        try:
781 1879e310 Stavros Sachtouris
            self.container = container or cnt_back_up
782 1879e310 Stavros Sachtouris
            return filter_in(
783 1879e310 Stavros Sachtouris
                self.get_container_info(),
784 1879e310 Stavros Sachtouris
                'X-Container-Policy-Quota')
785 1879e310 Stavros Sachtouris
        finally:
786 1879e310 Stavros Sachtouris
            self.container = cnt_back_up
787 e6b39366 Stavros Sachtouris
788 3dabe5d2 Stavros Sachtouris
    def get_container_info(self, until=None):
789 4375e020 Stavros Sachtouris
        """
790 4375e020 Stavros Sachtouris
        :param until: (str) formated date
791 4375e020 Stavros Sachtouris

792 4375e020 Stavros Sachtouris
        :returns: (dict)
793 f91bc6b1 Stavros Sachtouris

794 f91bc6b1 Stavros Sachtouris
        :raises ClientError: 404 Container not found
795 4375e020 Stavros Sachtouris
        """
796 f91bc6b1 Stavros Sachtouris
        try:
797 f91bc6b1 Stavros Sachtouris
            r = self.container_head(until=until)
798 f91bc6b1 Stavros Sachtouris
        except ClientError as err:
799 f91bc6b1 Stavros Sachtouris
            err.details.append('for container %s' % self.container)
800 f91bc6b1 Stavros Sachtouris
            raise err
801 8af4cc0b Stavros Sachtouris
        return r.headers
802 8af4cc0b Stavros Sachtouris
803 3dabe5d2 Stavros Sachtouris
    def get_container_meta(self, until=None):
804 4375e020 Stavros Sachtouris
        """
805 4375e020 Stavros Sachtouris
        :param until: (str) formated date
806 4375e020 Stavros Sachtouris

807 4375e020 Stavros Sachtouris
        :returns: (dict)
808 4375e020 Stavros Sachtouris
        """
809 24ff0a35 Stavros Sachtouris
        return filter_in(
810 24ff0a35 Stavros Sachtouris
            self.get_container_info(until=until),
811 3dabe5d2 Stavros Sachtouris
            'X-Container-Meta')
812 e6b39366 Stavros Sachtouris
813 3dabe5d2 Stavros Sachtouris
    def get_container_object_meta(self, until=None):
814 4375e020 Stavros Sachtouris
        """
815 4375e020 Stavros Sachtouris
        :param until: (str) formated date
816 4375e020 Stavros Sachtouris

817 4375e020 Stavros Sachtouris
        :returns: (dict)
818 4375e020 Stavros Sachtouris
        """
819 24ff0a35 Stavros Sachtouris
        return filter_in(
820 24ff0a35 Stavros Sachtouris
            self.get_container_info(until=until),
821 3dabe5d2 Stavros Sachtouris
            'X-Container-Object-Meta')
822 e6b39366 Stavros Sachtouris
823 af3b2b36 Stavros Sachtouris
    def set_container_meta(self, metapairs):
824 4375e020 Stavros Sachtouris
        """
825 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
826 4375e020 Stavros Sachtouris
        """
827 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
828 6ce9fc72 Stavros Sachtouris
        r = self.container_post(update=True, metadata=metapairs)
829 6ce9fc72 Stavros Sachtouris
        r.release()
830 3dabe5d2 Stavros Sachtouris
831 3e544e5b Stavros Sachtouris
    def del_container_meta(self, metakey):
832 4375e020 Stavros Sachtouris
        """
833 4375e020 Stavros Sachtouris
        :param metakey: (str) metadatum key
834 4375e020 Stavros Sachtouris
        """
835 3dabe5d2 Stavros Sachtouris
        r = self.container_post(update=True, metadata={metakey: ''})
836 6ce9fc72 Stavros Sachtouris
        r.release()
837 e6b39366 Stavros Sachtouris
838 d1856abf Stavros Sachtouris
    def set_container_quota(self, quota):
839 4375e020 Stavros Sachtouris
        """
840 4375e020 Stavros Sachtouris
        :param quota: (int)
841 4375e020 Stavros Sachtouris
        """
842 6ce9fc72 Stavros Sachtouris
        r = self.container_post(update=True, quota=quota)
843 6ce9fc72 Stavros Sachtouris
        r.release()
844 d1856abf Stavros Sachtouris
845 d1856abf Stavros Sachtouris
    def set_container_versioning(self, versioning):
846 4375e020 Stavros Sachtouris
        """
847 4375e020 Stavros Sachtouris
        :param versioning: (str)
848 4375e020 Stavros Sachtouris
        """
849 6ce9fc72 Stavros Sachtouris
        r = self.container_post(update=True, versioning=versioning)
850 6ce9fc72 Stavros Sachtouris
        r.release()
851 d1856abf Stavros Sachtouris
852 a298f2ab Stavros Sachtouris
    def del_object(self, obj, until=None, delimiter=None):
853 4375e020 Stavros Sachtouris
        """
854 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
855 4375e020 Stavros Sachtouris

856 4375e020 Stavros Sachtouris
        :param until: (str) formated date
857 4375e020 Stavros Sachtouris

858 4375e020 Stavros Sachtouris
        :param delimiter: (str)
859 4375e020 Stavros Sachtouris
        """
860 277ca4ed Dionysis Zindros
        self._assert_container()
861 6ce9fc72 Stavros Sachtouris
        r = self.object_delete(obj, until=until, delimiter=delimiter)
862 6ce9fc72 Stavros Sachtouris
        r.release()
863 a298f2ab Stavros Sachtouris
864 4375e020 Stavros Sachtouris
    def set_object_meta(self, obj, metapairs):
865 4375e020 Stavros Sachtouris
        """
866 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
867 4375e020 Stavros Sachtouris

868 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
869 4375e020 Stavros Sachtouris
        """
870 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
871 4375e020 Stavros Sachtouris
        r = self.object_post(obj, update=True, metadata=metapairs)
872 6ce9fc72 Stavros Sachtouris
        r.release()
873 87688514 Stavros Sachtouris
874 bc223d91 Stavros Sachtouris
    def del_object_meta(self, obj, metakey):
875 4375e020 Stavros Sachtouris
        """
876 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
877 bc223d91 Stavros Sachtouris

878 bc223d91 Stavros Sachtouris
        :param metakey: (str) metadatum key
879 4375e020 Stavros Sachtouris
        """
880 5fb18128 Stavros Sachtouris
        r = self.object_post(obj, update=True, metadata={metakey: ''})
881 6ce9fc72 Stavros Sachtouris
        r.release()
882 6de1f262 Stavros Sachtouris
883 bc223d91 Stavros Sachtouris
    def publish_object(self, obj):
884 bc223d91 Stavros Sachtouris
        """
885 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
886 5260a313 Stavros Sachtouris

887 5260a313 Stavros Sachtouris
        :returns: (str) access url
888 bc223d91 Stavros Sachtouris
        """
889 bc223d91 Stavros Sachtouris
        r = self.object_post(obj, update=True, public=True)
890 6ce9fc72 Stavros Sachtouris
        r.release()
891 5260a313 Stavros Sachtouris
        info = self.get_object_info(obj)
892 93542587 Stavros Sachtouris
        pref, sep, rest = self.base_url.partition('//')
893 93542587 Stavros Sachtouris
        base = rest.split('/')[0]
894 24ff0a35 Stavros Sachtouris
        newurl = path4url(
895 24ff0a35 Stavros Sachtouris
            '%s%s%s' % (pref, sep, base),
896 93542587 Stavros Sachtouris
            info['x-object-public'])
897 5260a313 Stavros Sachtouris
        return newurl[1:]
898 87688514 Stavros Sachtouris
899 bc223d91 Stavros Sachtouris
    def unpublish_object(self, obj):
900 bc223d91 Stavros Sachtouris
        """
901 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
902 bc223d91 Stavros Sachtouris
        """
903 bc223d91 Stavros Sachtouris
        r = self.object_post(obj, update=True, public=False)
904 6ce9fc72 Stavros Sachtouris
        r.release()
905 28470086 Stavros Sachtouris
906 8af4cc0b Stavros Sachtouris
    def get_object_info(self, obj, version=None):
907 bc223d91 Stavros Sachtouris
        """
908 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
909 bc223d91 Stavros Sachtouris

910 bc223d91 Stavros Sachtouris
        :param version: (str)
911 bc223d91 Stavros Sachtouris

912 bc223d91 Stavros Sachtouris
        :returns: (dict)
913 bc223d91 Stavros Sachtouris
        """
914 ca092af4 Stavros Sachtouris
        try:
915 ca092af4 Stavros Sachtouris
            r = self.object_head(obj, version=version)
916 ca092af4 Stavros Sachtouris
            return r.headers
917 ca092af4 Stavros Sachtouris
        except ClientError as ce:
918 ca092af4 Stavros Sachtouris
            if ce.status == 404:
919 723e9d47 Stavros Sachtouris
                raise ClientError('Object %s not found' % obj, status=404)
920 ca092af4 Stavros Sachtouris
            raise
921 8af4cc0b Stavros Sachtouris
922 8af4cc0b Stavros Sachtouris
    def get_object_meta(self, obj, version=None):
923 bc223d91 Stavros Sachtouris
        """
924 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
925 bc223d91 Stavros Sachtouris

926 bc223d91 Stavros Sachtouris
        :param version: (str)
927 bc223d91 Stavros Sachtouris

928 bc223d91 Stavros Sachtouris
        :returns: (dict)
929 bc223d91 Stavros Sachtouris
        """
930 24ff0a35 Stavros Sachtouris
        return filter_in(
931 24ff0a35 Stavros Sachtouris
            self.get_object_info(obj, version=version),
932 3dabe5d2 Stavros Sachtouris
            'X-Object-Meta')
933 8af4cc0b Stavros Sachtouris
934 bc223d91 Stavros Sachtouris
    def get_object_sharing(self, obj):
935 bc223d91 Stavros Sachtouris
        """
936 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
937 bc223d91 Stavros Sachtouris

938 bc223d91 Stavros Sachtouris
        :returns: (dict)
939 bc223d91 Stavros Sachtouris
        """
940 24ff0a35 Stavros Sachtouris
        r = filter_in(
941 24ff0a35 Stavros Sachtouris
            self.get_object_info(obj),
942 3dabe5d2 Stavros Sachtouris
            'X-Object-Sharing',
943 3dabe5d2 Stavros Sachtouris
            exactMatch=True)
944 f70616fc Stavros Sachtouris
        reply = {}
945 f70616fc Stavros Sachtouris
        if len(r) > 0:
946 f70616fc Stavros Sachtouris
            perms = r['x-object-sharing'].split(';')
947 f70616fc Stavros Sachtouris
            for perm in perms:
948 f70616fc Stavros Sachtouris
                try:
949 f70616fc Stavros Sachtouris
                    perm.index('=')
950 f70616fc Stavros Sachtouris
                except ValueError:
951 f70616fc Stavros Sachtouris
                    raise ClientError('Incorrect reply format')
952 f70616fc Stavros Sachtouris
                (key, val) = perm.strip().split('=')
953 f70616fc Stavros Sachtouris
                reply[key] = val
954 f70616fc Stavros Sachtouris
        return reply
955 f49084df Stavros Sachtouris
956 24ff0a35 Stavros Sachtouris
    def set_object_sharing(
957 2005b18e Stavros Sachtouris
            self, obj,
958 2005b18e Stavros Sachtouris
            read_permition=False, write_permition=False):
959 28470086 Stavros Sachtouris
        """Give read/write permisions to an object.
960 bc223d91 Stavros Sachtouris

961 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
962 bc223d91 Stavros Sachtouris

963 bc223d91 Stavros Sachtouris
        :param read_permition: (list - bool) users and user groups that get
964 bc223d91 Stavros Sachtouris
            read permition for this object - False means all previous read
965 bc223d91 Stavros Sachtouris
            permissions will be removed
966 bc223d91 Stavros Sachtouris

967 bc223d91 Stavros Sachtouris
        :param write_perimition: (list - bool) of users and user groups to get
968 bc223d91 Stavros Sachtouris
           write permition for this object - False means all previous write
969 4067cdaf Stavros Sachtouris
           permissions will be removed
970 28470086 Stavros Sachtouris
        """
971 4067cdaf Stavros Sachtouris
972 24ff0a35 Stavros Sachtouris
        perms = dict(
973 24ff0a35 Stavros Sachtouris
            read='' if not read_permition else read_permition,
974 3dabe5d2 Stavros Sachtouris
            write='' if not write_permition else write_permition)
975 bc223d91 Stavros Sachtouris
        r = self.object_post(obj, update=True, permissions=perms)
976 6ce9fc72 Stavros Sachtouris
        r.release()
977 28470086 Stavros Sachtouris
978 bc223d91 Stavros Sachtouris
    def del_object_sharing(self, obj):
979 bc223d91 Stavros Sachtouris
        """
980 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
981 bc223d91 Stavros Sachtouris
        """
982 bc223d91 Stavros Sachtouris
        self.set_object_sharing(obj)
983 bc223d91 Stavros Sachtouris
984 bc223d91 Stavros Sachtouris
    def append_object(self, obj, source_file, upload_cb=None):
985 bc223d91 Stavros Sachtouris
        """
986 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
987 bc223d91 Stavros Sachtouris

988 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
989 f49084df Stavros Sachtouris

990 bc223d91 Stavros Sachtouris
        :param upload_db: progress.bar for uploading
991 bcabbc35 Stavros Sachtouris
        """
992 4067cdaf Stavros Sachtouris
993 277ca4ed Dionysis Zindros
        self._assert_container()
994 2f749e6e Stavros Sachtouris
        meta = self.get_container_info()
995 ab474306 Stavros Sachtouris
        blocksize = int(meta['x-container-block-size'])
996 64ab4c13 Stavros Sachtouris
        filesize = fstat(source_file.fileno()).st_size
997 3dabe5d2 Stavros Sachtouris
        nblocks = 1 + (filesize - 1) // blocksize
998 ab474306 Stavros Sachtouris
        offset = 0
999 ca092af4 Stavros Sachtouris
        if upload_cb:
1000 bcabbc35 Stavros Sachtouris
            upload_gen = upload_cb(nblocks)
1001 ca092af4 Stavros Sachtouris
            upload_gen.next()
1002 ab474306 Stavros Sachtouris
        for i in range(nblocks):
1003 ab474306 Stavros Sachtouris
            block = source_file.read(min(blocksize, filesize - offset))
1004 ab474306 Stavros Sachtouris
            offset += len(block)
1005 24ff0a35 Stavros Sachtouris
            r = self.object_post(
1006 24ff0a35 Stavros Sachtouris
                obj,
1007 3dabe5d2 Stavros Sachtouris
                update=True,
1008 3dabe5d2 Stavros Sachtouris
                content_range='bytes */*',
1009 3dabe5d2 Stavros Sachtouris
                content_type='application/octet-stream',
1010 3dabe5d2 Stavros Sachtouris
                content_length=len(block),
1011 3dabe5d2 Stavros Sachtouris
                data=block)
1012 6ce9fc72 Stavros Sachtouris
            r.release()
1013 3dabe5d2 Stavros Sachtouris
1014 ca092af4 Stavros Sachtouris
            if upload_cb:
1015 bcabbc35 Stavros Sachtouris
                upload_gen.next()
1016 561116a6 Stavros Sachtouris
1017 bc223d91 Stavros Sachtouris
    def truncate_object(self, obj, upto_bytes):
1018 bc223d91 Stavros Sachtouris
        """
1019 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1020 bc223d91 Stavros Sachtouris

1021 bc223d91 Stavros Sachtouris
        :param upto_bytes: max number of bytes to leave on file
1022 bc223d91 Stavros Sachtouris
        """
1023 24ff0a35 Stavros Sachtouris
        r = self.object_post(
1024 24ff0a35 Stavros Sachtouris
            obj,
1025 3dabe5d2 Stavros Sachtouris
            update=True,
1026 3dabe5d2 Stavros Sachtouris
            content_range='bytes 0-%s/*' % upto_bytes,
1027 3dabe5d2 Stavros Sachtouris
            content_type='application/octet-stream',
1028 3dabe5d2 Stavros Sachtouris
            object_bytes=upto_bytes,
1029 bc223d91 Stavros Sachtouris
            source_object=path4url(self.container, obj))
1030 6ce9fc72 Stavros Sachtouris
        r.release()
1031 ee62607e Stavros Sachtouris
1032 2005b18e Stavros Sachtouris
    def overwrite_object(self, obj, start, end, source_file, upload_cb=None):
1033 bc223d91 Stavros Sachtouris
        """Overwrite a part of an object from local source file
1034 bc223d91 Stavros Sachtouris

1035 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1036 bc223d91 Stavros Sachtouris

1037 bc223d91 Stavros Sachtouris
        :param start: (int) position in bytes to start overwriting from
1038 bc223d91 Stavros Sachtouris

1039 bc223d91 Stavros Sachtouris
        :param end: (int) position in bytes to stop overwriting at
1040 bc223d91 Stavros Sachtouris

1041 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
1042 bc223d91 Stavros Sachtouris

1043 bc223d91 Stavros Sachtouris
        :param upload_db: progress.bar for uploading
1044 ee62607e Stavros Sachtouris
        """
1045 4067cdaf Stavros Sachtouris
1046 ca092af4 Stavros Sachtouris
        r = self.get_object_info(obj)
1047 ca092af4 Stavros Sachtouris
        rf_size = int(r['content-length'])
1048 ca092af4 Stavros Sachtouris
        if rf_size < int(start):
1049 ca092af4 Stavros Sachtouris
            raise ClientError(
1050 ca092af4 Stavros Sachtouris
                'Range start exceeds file size',
1051 ca092af4 Stavros Sachtouris
                status=416)
1052 ca092af4 Stavros Sachtouris
        elif rf_size < int(end):
1053 ca092af4 Stavros Sachtouris
            raise ClientError(
1054 ca092af4 Stavros Sachtouris
                'Range end exceeds file size',
1055 ca092af4 Stavros Sachtouris
                status=416)
1056 277ca4ed Dionysis Zindros
        self._assert_container()
1057 2f749e6e Stavros Sachtouris
        meta = self.get_container_info()
1058 ee62607e Stavros Sachtouris
        blocksize = int(meta['x-container-block-size'])
1059 64ab4c13 Stavros Sachtouris
        filesize = fstat(source_file.fileno()).st_size
1060 ee62607e Stavros Sachtouris
        datasize = int(end) - int(start) + 1
1061 3dabe5d2 Stavros Sachtouris
        nblocks = 1 + (datasize - 1) // blocksize
1062 ee62607e Stavros Sachtouris
        offset = 0
1063 ca092af4 Stavros Sachtouris
        if upload_cb:
1064 bcabbc35 Stavros Sachtouris
            upload_gen = upload_cb(nblocks)
1065 ca092af4 Stavros Sachtouris
            upload_gen.next()
1066 ee62607e Stavros Sachtouris
        for i in range(nblocks):
1067 24ff0a35 Stavros Sachtouris
            read_size = min(blocksize, filesize - offset, datasize - offset)
1068 24ff0a35 Stavros Sachtouris
            block = source_file.read(read_size)
1069 24ff0a35 Stavros Sachtouris
            r = self.object_post(
1070 24ff0a35 Stavros Sachtouris
                obj,
1071 3dabe5d2 Stavros Sachtouris
                update=True,
1072 3dabe5d2 Stavros Sachtouris
                content_type='application/octet-stream',
1073 3dabe5d2 Stavros Sachtouris
                content_length=len(block),
1074 ca092af4 Stavros Sachtouris
                content_range='bytes %s-%s/*' % (
1075 ca092af4 Stavros Sachtouris
                    start + offset,
1076 ca092af4 Stavros Sachtouris
                    start + offset + len(block) - 1),
1077 3dabe5d2 Stavros Sachtouris
                data=block)
1078 ca092af4 Stavros Sachtouris
            offset += len(block)
1079 6ce9fc72 Stavros Sachtouris
            r.release()
1080 3dabe5d2 Stavros Sachtouris
1081 ca092af4 Stavros Sachtouris
            if upload_cb:
1082 bcabbc35 Stavros Sachtouris
                upload_gen.next()
1083 7d420701 Stavros Sachtouris
1084 24ff0a35 Stavros Sachtouris
    def copy_object(
1085 2005b18e Stavros Sachtouris
            self, src_container, src_object, dst_container,
1086 33487500 Stavros Sachtouris
            dst_object=None,
1087 2005b18e Stavros Sachtouris
            source_version=None,
1088 3a066af4 Stavros Sachtouris
            source_account=None,
1089 2005b18e Stavros Sachtouris
            public=False,
1090 2005b18e Stavros Sachtouris
            content_type=None,
1091 2005b18e Stavros Sachtouris
            delimiter=None):
1092 bc223d91 Stavros Sachtouris
        """
1093 bc223d91 Stavros Sachtouris
        :param src_container: (str) source container
1094 bc223d91 Stavros Sachtouris

1095 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1096 bc223d91 Stavros Sachtouris

1097 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1098 bc223d91 Stavros Sachtouris

1099 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1100 bc223d91 Stavros Sachtouris

1101 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1102 bc223d91 Stavros Sachtouris

1103 3a066af4 Stavros Sachtouris
        :param source_account: (str) account to copy from
1104 3a066af4 Stavros Sachtouris

1105 bc223d91 Stavros Sachtouris
        :param public: (bool)
1106 bc223d91 Stavros Sachtouris

1107 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1108 bc223d91 Stavros Sachtouris

1109 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1110 bc223d91 Stavros Sachtouris
        """
1111 277ca4ed Dionysis Zindros
        self._assert_account()
1112 7d420701 Stavros Sachtouris
        self.container = dst_container
1113 7d420701 Stavros Sachtouris
        src_path = path4url(src_container, src_object)
1114 24ff0a35 Stavros Sachtouris
        r = self.object_put(
1115 33487500 Stavros Sachtouris
            dst_object or src_object,
1116 3dabe5d2 Stavros Sachtouris
            success=201,
1117 3dabe5d2 Stavros Sachtouris
            copy_from=src_path,
1118 3dabe5d2 Stavros Sachtouris
            content_length=0,
1119 3dabe5d2 Stavros Sachtouris
            source_version=source_version,
1120 3a066af4 Stavros Sachtouris
            source_account=source_account,
1121 3dabe5d2 Stavros Sachtouris
            public=public,
1122 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
1123 7d420701 Stavros Sachtouris
            delimiter=delimiter)
1124 6ce9fc72 Stavros Sachtouris
        r.release()
1125 a5e0629d Stavros Sachtouris
1126 24ff0a35 Stavros Sachtouris
    def move_object(
1127 24ff0a35 Stavros Sachtouris
            self, src_container, src_object, dst_container,
1128 24ff0a35 Stavros Sachtouris
            dst_object=False,
1129 4f266635 Stavros Sachtouris
            source_account=None,
1130 24ff0a35 Stavros Sachtouris
            source_version=None,
1131 24ff0a35 Stavros Sachtouris
            public=False,
1132 24ff0a35 Stavros Sachtouris
            content_type=None,
1133 24ff0a35 Stavros Sachtouris
            delimiter=None):
1134 bc223d91 Stavros Sachtouris
        """
1135 bc223d91 Stavros Sachtouris
        :param src_container: (str) source container
1136 bc223d91 Stavros Sachtouris

1137 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1138 bc223d91 Stavros Sachtouris

1139 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1140 bc223d91 Stavros Sachtouris

1141 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1142 bc223d91 Stavros Sachtouris

1143 4f266635 Stavros Sachtouris
        :param source_account: (str) account to move from
1144 4f266635 Stavros Sachtouris

1145 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1146 bc223d91 Stavros Sachtouris

1147 bc223d91 Stavros Sachtouris
        :param public: (bool)
1148 bc223d91 Stavros Sachtouris

1149 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1150 bc223d91 Stavros Sachtouris

1151 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1152 bc223d91 Stavros Sachtouris
        """
1153 277ca4ed Dionysis Zindros
        self._assert_account()
1154 a5e0629d Stavros Sachtouris
        self.container = dst_container
1155 a5e0629d Stavros Sachtouris
        dst_object = dst_object or src_object
1156 a5e0629d Stavros Sachtouris
        src_path = path4url(src_container, src_object)
1157 24ff0a35 Stavros Sachtouris
        r = self.object_put(
1158 24ff0a35 Stavros Sachtouris
            dst_object,
1159 3dabe5d2 Stavros Sachtouris
            success=201,
1160 3dabe5d2 Stavros Sachtouris
            move_from=src_path,
1161 3dabe5d2 Stavros Sachtouris
            content_length=0,
1162 4f266635 Stavros Sachtouris
            source_account=source_account,
1163 3dabe5d2 Stavros Sachtouris
            source_version=source_version,
1164 3dabe5d2 Stavros Sachtouris
            public=public,
1165 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
1166 a23f6ffe Stavros Sachtouris
            delimiter=delimiter)
1167 6ce9fc72 Stavros Sachtouris
        r.release()
1168 a23f6ffe Stavros Sachtouris
1169 a23f6ffe Stavros Sachtouris
    def get_sharing_accounts(self, limit=None, marker=None, *args, **kwargs):
1170 bc223d91 Stavros Sachtouris
        """Get accounts that share with self.account
1171 bc223d91 Stavros Sachtouris

1172 bc223d91 Stavros Sachtouris
        :param limit: (str)
1173 bc223d91 Stavros Sachtouris

1174 bc223d91 Stavros Sachtouris
        :param marker: (str)
1175 bc223d91 Stavros Sachtouris

1176 bc223d91 Stavros Sachtouris
        :returns: (dict)
1177 bc223d91 Stavros Sachtouris
        """
1178 277ca4ed Dionysis Zindros
        self._assert_account()
1179 a23f6ffe Stavros Sachtouris
1180 3dabe5d2 Stavros Sachtouris
        self.set_param('format', 'json')
1181 3dabe5d2 Stavros Sachtouris
        self.set_param('limit', limit, iff=limit is not None)
1182 3dabe5d2 Stavros Sachtouris
        self.set_param('marker', marker, iff=marker is not None)
1183 a23f6ffe Stavros Sachtouris
1184 a23f6ffe Stavros Sachtouris
        path = ''
1185 a23f6ffe Stavros Sachtouris
        success = kwargs.pop('success', (200, 204))
1186 3dabe5d2 Stavros Sachtouris
        r = self.get(path, *args, success=success, **kwargs)
1187 38dc5d2f Stavros Sachtouris
        return r.json
1188 38dc5d2f Stavros Sachtouris
1189 bc223d91 Stavros Sachtouris
    def get_object_versionlist(self, obj):
1190 bc223d91 Stavros Sachtouris
        """
1191 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1192 bc223d91 Stavros Sachtouris

1193 bc223d91 Stavros Sachtouris
        :returns: (list)
1194 bc223d91 Stavros Sachtouris
        """
1195 277ca4ed Dionysis Zindros
        self._assert_container()
1196 bc223d91 Stavros Sachtouris
        r = self.object_get(obj, format='json', version='list')
1197 38dc5d2f Stavros Sachtouris
        return r.json['versions']