Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / pithos.py @ f5f2dc53

History | View | Annotate | Download (35.4 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 17edd3f4 Stavros Sachtouris
    def purge_container(self):
77 4375e020 Stavros Sachtouris
        """Delete an empty container and destroy associated blocks
78 4375e020 Stavros Sachtouris
        """
79 6ce9fc72 Stavros Sachtouris
        r = self.container_delete(until=unicode(time()))
80 6ce9fc72 Stavros Sachtouris
        r.release()
81 3dabe5d2 Stavros Sachtouris
82 24ff0a35 Stavros Sachtouris
    def upload_object_unchunked(
83 24ff0a35 Stavros Sachtouris
            self, obj, f,
84 24ff0a35 Stavros Sachtouris
            withHashFile=False,
85 24ff0a35 Stavros Sachtouris
            size=None,
86 24ff0a35 Stavros Sachtouris
            etag=None,
87 24ff0a35 Stavros Sachtouris
            content_encoding=None,
88 24ff0a35 Stavros Sachtouris
            content_disposition=None,
89 24ff0a35 Stavros Sachtouris
            content_type=None,
90 24ff0a35 Stavros Sachtouris
            sharing=None,
91 24ff0a35 Stavros Sachtouris
            public=None):
92 4375e020 Stavros Sachtouris
        """
93 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
94 4375e020 Stavros Sachtouris

95 4375e020 Stavros Sachtouris
        :param f: open file descriptor
96 4375e020 Stavros Sachtouris

97 4375e020 Stavros Sachtouris
        :param withHashFile: (bool)
98 4375e020 Stavros Sachtouris

99 4375e020 Stavros Sachtouris
        :param size: (int) size of data to upload
100 4375e020 Stavros Sachtouris

101 4375e020 Stavros Sachtouris
        :param etag: (str)
102 4375e020 Stavros Sachtouris

103 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
104 4375e020 Stavros Sachtouris

105 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
106 4375e020 Stavros Sachtouris

107 4375e020 Stavros Sachtouris
        :param content_type: (str)
108 4375e020 Stavros Sachtouris

109 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
110 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
111 4375e020 Stavros Sachtouris

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

151 4375e020 Stavros Sachtouris
        :param etag: (str)
152 4375e020 Stavros Sachtouris

153 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
154 4375e020 Stavros Sachtouris

155 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
156 4375e020 Stavros Sachtouris

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

159 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
160 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
161 4375e020 Stavros Sachtouris

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

308 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
309 4375e020 Stavros Sachtouris

310 4375e020 Stavros Sachtouris
        :param f: open file descriptor (rb)
311 4375e020 Stavros Sachtouris

312 4375e020 Stavros Sachtouris
        :param hash_cb: optional progress.bar object for calculating hashes
313 4375e020 Stavros Sachtouris

314 4375e020 Stavros Sachtouris
        :param upload_cb: optional progress.bar object for uploading
315 4375e020 Stavros Sachtouris

316 4375e020 Stavros Sachtouris
        :param etag: (str)
317 4375e020 Stavros Sachtouris

318 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
319 4375e020 Stavros Sachtouris

320 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
321 4375e020 Stavros Sachtouris

322 4375e020 Stavros Sachtouris
        :param content_type: (str)
323 4375e020 Stavros Sachtouris

324 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
325 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
326 4375e020 Stavros Sachtouris

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

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

516 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
517 4375e020 Stavros Sachtouris

518 4375e020 Stavros Sachtouris
        :param dst: open file descriptor (wb+)
519 4375e020 Stavros Sachtouris

520 4375e020 Stavros Sachtouris
        :param download_cb: optional progress.bar object for downloading
521 4375e020 Stavros Sachtouris

522 4375e020 Stavros Sachtouris
        :param version: (str) file version
523 4375e020 Stavros Sachtouris

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

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

528 4375e020 Stavros Sachtouris
        :param if_match: (str)
529 4375e020 Stavros Sachtouris

530 4375e020 Stavros Sachtouris
        :param if_none_match: (str)
531 4375e020 Stavros Sachtouris

532 4375e020 Stavros Sachtouris
        :param if_modified_since: (str) formated date
533 4375e020 Stavros Sachtouris

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

606 4375e020 Stavros Sachtouris
        :param if_match: (str)
607 4375e020 Stavros Sachtouris

608 4375e020 Stavros Sachtouris
        :param if_none_match: (str)
609 4375e020 Stavros Sachtouris

610 4375e020 Stavros Sachtouris
        :param if_modified_since: (str) formated date
611 4375e020 Stavros Sachtouris

612 4375e020 Stavros Sachtouris
        :param if_unmodified_since: (str) formated date
613 4375e020 Stavros Sachtouris

614 4375e020 Stavros Sachtouris
        :param data_range: (str) from-to where from and to are integers
615 4375e020 Stavros Sachtouris
            denoting file positions in bytes
616 4375e020 Stavros Sachtouris

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

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

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

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

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

736 4375e020 Stavros Sachtouris
        :raises ClientError: 404 Container does not exist
737 4375e020 Stavros Sachtouris

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

759 4375e020 Stavros Sachtouris
        :returns: (dict)
760 4375e020 Stavros Sachtouris
        """
761 2f749e6e Stavros Sachtouris
        self.container = container
762 24ff0a35 Stavros Sachtouris
        return filter_in(
763 24ff0a35 Stavros Sachtouris
            self.get_container_info(),
764 3dabe5d2 Stavros Sachtouris
            'X-Container-Policy-Versioning')
765 d1856abf Stavros Sachtouris
766 d1856abf Stavros Sachtouris
    def get_container_quota(self, container):
767 4375e020 Stavros Sachtouris
        """
768 4375e020 Stavros Sachtouris
        :param container: (str)
769 4375e020 Stavros Sachtouris

770 4375e020 Stavros Sachtouris
        :returns: (dict)
771 4375e020 Stavros Sachtouris
        """
772 2f749e6e Stavros Sachtouris
        self.container = container
773 2f749e6e Stavros Sachtouris
        return filter_in(self.get_container_info(), 'X-Container-Policy-Quota')
774 e6b39366 Stavros Sachtouris
775 3dabe5d2 Stavros Sachtouris
    def get_container_info(self, until=None):
776 4375e020 Stavros Sachtouris
        """
777 4375e020 Stavros Sachtouris
        :param until: (str) formated date
778 4375e020 Stavros Sachtouris

779 4375e020 Stavros Sachtouris
        :returns: (dict)
780 f91bc6b1 Stavros Sachtouris

781 f91bc6b1 Stavros Sachtouris
        :raises ClientError: 404 Container not found
782 4375e020 Stavros Sachtouris
        """
783 f91bc6b1 Stavros Sachtouris
        try:
784 f91bc6b1 Stavros Sachtouris
            r = self.container_head(until=until)
785 f91bc6b1 Stavros Sachtouris
        except ClientError as err:
786 f91bc6b1 Stavros Sachtouris
            err.details.append('for container %s' % self.container)
787 f91bc6b1 Stavros Sachtouris
            raise err
788 8af4cc0b Stavros Sachtouris
        return r.headers
789 8af4cc0b Stavros Sachtouris
790 3dabe5d2 Stavros Sachtouris
    def get_container_meta(self, until=None):
791 4375e020 Stavros Sachtouris
        """
792 4375e020 Stavros Sachtouris
        :param until: (str) formated date
793 4375e020 Stavros Sachtouris

794 4375e020 Stavros Sachtouris
        :returns: (dict)
795 4375e020 Stavros Sachtouris
        """
796 24ff0a35 Stavros Sachtouris
        return filter_in(
797 24ff0a35 Stavros Sachtouris
            self.get_container_info(until=until),
798 3dabe5d2 Stavros Sachtouris
            'X-Container-Meta')
799 e6b39366 Stavros Sachtouris
800 3dabe5d2 Stavros Sachtouris
    def get_container_object_meta(self, until=None):
801 4375e020 Stavros Sachtouris
        """
802 4375e020 Stavros Sachtouris
        :param until: (str) formated date
803 4375e020 Stavros Sachtouris

804 4375e020 Stavros Sachtouris
        :returns: (dict)
805 4375e020 Stavros Sachtouris
        """
806 24ff0a35 Stavros Sachtouris
        return filter_in(
807 24ff0a35 Stavros Sachtouris
            self.get_container_info(until=until),
808 3dabe5d2 Stavros Sachtouris
            'X-Container-Object-Meta')
809 e6b39366 Stavros Sachtouris
810 af3b2b36 Stavros Sachtouris
    def set_container_meta(self, metapairs):
811 4375e020 Stavros Sachtouris
        """
812 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
813 4375e020 Stavros Sachtouris
        """
814 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
815 6ce9fc72 Stavros Sachtouris
        r = self.container_post(update=True, metadata=metapairs)
816 6ce9fc72 Stavros Sachtouris
        r.release()
817 3dabe5d2 Stavros Sachtouris
818 3e544e5b Stavros Sachtouris
    def del_container_meta(self, metakey):
819 4375e020 Stavros Sachtouris
        """
820 4375e020 Stavros Sachtouris
        :param metakey: (str) metadatum key
821 4375e020 Stavros Sachtouris
        """
822 3dabe5d2 Stavros Sachtouris
        r = self.container_post(update=True, metadata={metakey: ''})
823 6ce9fc72 Stavros Sachtouris
        r.release()
824 e6b39366 Stavros Sachtouris
825 d1856abf Stavros Sachtouris
    def set_container_quota(self, quota):
826 4375e020 Stavros Sachtouris
        """
827 4375e020 Stavros Sachtouris
        :param quota: (int)
828 4375e020 Stavros Sachtouris
        """
829 6ce9fc72 Stavros Sachtouris
        r = self.container_post(update=True, quota=quota)
830 6ce9fc72 Stavros Sachtouris
        r.release()
831 d1856abf Stavros Sachtouris
832 d1856abf Stavros Sachtouris
    def set_container_versioning(self, versioning):
833 4375e020 Stavros Sachtouris
        """
834 4375e020 Stavros Sachtouris
        :param versioning: (str)
835 4375e020 Stavros Sachtouris
        """
836 6ce9fc72 Stavros Sachtouris
        r = self.container_post(update=True, versioning=versioning)
837 6ce9fc72 Stavros Sachtouris
        r.release()
838 d1856abf Stavros Sachtouris
839 a298f2ab Stavros Sachtouris
    def del_object(self, obj, until=None, delimiter=None):
840 4375e020 Stavros Sachtouris
        """
841 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
842 4375e020 Stavros Sachtouris

843 4375e020 Stavros Sachtouris
        :param until: (str) formated date
844 4375e020 Stavros Sachtouris

845 4375e020 Stavros Sachtouris
        :param delimiter: (str)
846 4375e020 Stavros Sachtouris
        """
847 277ca4ed Dionysis Zindros
        self._assert_container()
848 6ce9fc72 Stavros Sachtouris
        r = self.object_delete(obj, until=until, delimiter=delimiter)
849 6ce9fc72 Stavros Sachtouris
        r.release()
850 a298f2ab Stavros Sachtouris
851 4375e020 Stavros Sachtouris
    def set_object_meta(self, obj, metapairs):
852 4375e020 Stavros Sachtouris
        """
853 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
854 4375e020 Stavros Sachtouris

855 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
856 4375e020 Stavros Sachtouris
        """
857 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
858 4375e020 Stavros Sachtouris
        r = self.object_post(obj, update=True, metadata=metapairs)
859 6ce9fc72 Stavros Sachtouris
        r.release()
860 87688514 Stavros Sachtouris
861 bc223d91 Stavros Sachtouris
    def del_object_meta(self, obj, metakey):
862 4375e020 Stavros Sachtouris
        """
863 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
864 bc223d91 Stavros Sachtouris

865 bc223d91 Stavros Sachtouris
        :param metakey: (str) metadatum key
866 4375e020 Stavros Sachtouris
        """
867 5fb18128 Stavros Sachtouris
        r = self.object_post(obj, update=True, metadata={metakey: ''})
868 6ce9fc72 Stavros Sachtouris
        r.release()
869 6de1f262 Stavros Sachtouris
870 bc223d91 Stavros Sachtouris
    def publish_object(self, obj):
871 bc223d91 Stavros Sachtouris
        """
872 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
873 5260a313 Stavros Sachtouris

874 5260a313 Stavros Sachtouris
        :returns: (str) access url
875 bc223d91 Stavros Sachtouris
        """
876 bc223d91 Stavros Sachtouris
        r = self.object_post(obj, update=True, public=True)
877 6ce9fc72 Stavros Sachtouris
        r.release()
878 5260a313 Stavros Sachtouris
        info = self.get_object_info(obj)
879 93542587 Stavros Sachtouris
        pref, sep, rest = self.base_url.partition('//')
880 93542587 Stavros Sachtouris
        base = rest.split('/')[0]
881 24ff0a35 Stavros Sachtouris
        newurl = path4url(
882 24ff0a35 Stavros Sachtouris
            '%s%s%s' % (pref, sep, base),
883 93542587 Stavros Sachtouris
            info['x-object-public'])
884 5260a313 Stavros Sachtouris
        return newurl[1:]
885 87688514 Stavros Sachtouris
886 bc223d91 Stavros Sachtouris
    def unpublish_object(self, obj):
887 bc223d91 Stavros Sachtouris
        """
888 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
889 bc223d91 Stavros Sachtouris
        """
890 bc223d91 Stavros Sachtouris
        r = self.object_post(obj, update=True, public=False)
891 6ce9fc72 Stavros Sachtouris
        r.release()
892 28470086 Stavros Sachtouris
893 8af4cc0b Stavros Sachtouris
    def get_object_info(self, obj, version=None):
894 bc223d91 Stavros Sachtouris
        """
895 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
896 bc223d91 Stavros Sachtouris

897 bc223d91 Stavros Sachtouris
        :param version: (str)
898 bc223d91 Stavros Sachtouris

899 bc223d91 Stavros Sachtouris
        :returns: (dict)
900 bc223d91 Stavros Sachtouris
        """
901 ca092af4 Stavros Sachtouris
        try:
902 ca092af4 Stavros Sachtouris
            r = self.object_head(obj, version=version)
903 ca092af4 Stavros Sachtouris
            return r.headers
904 ca092af4 Stavros Sachtouris
        except ClientError as ce:
905 ca092af4 Stavros Sachtouris
            if ce.status == 404:
906 ca092af4 Stavros Sachtouris
                raise ClientError('Object not found', status=404)
907 ca092af4 Stavros Sachtouris
            raise
908 8af4cc0b Stavros Sachtouris
909 8af4cc0b Stavros Sachtouris
    def get_object_meta(self, obj, version=None):
910 bc223d91 Stavros Sachtouris
        """
911 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
912 bc223d91 Stavros Sachtouris

913 bc223d91 Stavros Sachtouris
        :param version: (str)
914 bc223d91 Stavros Sachtouris

915 bc223d91 Stavros Sachtouris
        :returns: (dict)
916 bc223d91 Stavros Sachtouris
        """
917 24ff0a35 Stavros Sachtouris
        return filter_in(
918 24ff0a35 Stavros Sachtouris
            self.get_object_info(obj, version=version),
919 3dabe5d2 Stavros Sachtouris
            'X-Object-Meta')
920 8af4cc0b Stavros Sachtouris
921 bc223d91 Stavros Sachtouris
    def get_object_sharing(self, obj):
922 bc223d91 Stavros Sachtouris
        """
923 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
924 bc223d91 Stavros Sachtouris

925 bc223d91 Stavros Sachtouris
        :returns: (dict)
926 bc223d91 Stavros Sachtouris
        """
927 24ff0a35 Stavros Sachtouris
        r = filter_in(
928 24ff0a35 Stavros Sachtouris
            self.get_object_info(obj),
929 3dabe5d2 Stavros Sachtouris
            'X-Object-Sharing',
930 3dabe5d2 Stavros Sachtouris
            exactMatch=True)
931 f70616fc Stavros Sachtouris
        reply = {}
932 f70616fc Stavros Sachtouris
        if len(r) > 0:
933 f70616fc Stavros Sachtouris
            perms = r['x-object-sharing'].split(';')
934 f70616fc Stavros Sachtouris
            for perm in perms:
935 f70616fc Stavros Sachtouris
                try:
936 f70616fc Stavros Sachtouris
                    perm.index('=')
937 f70616fc Stavros Sachtouris
                except ValueError:
938 f70616fc Stavros Sachtouris
                    raise ClientError('Incorrect reply format')
939 f70616fc Stavros Sachtouris
                (key, val) = perm.strip().split('=')
940 f70616fc Stavros Sachtouris
                reply[key] = val
941 f70616fc Stavros Sachtouris
        return reply
942 f49084df Stavros Sachtouris
943 24ff0a35 Stavros Sachtouris
    def set_object_sharing(
944 2005b18e Stavros Sachtouris
            self, obj,
945 2005b18e Stavros Sachtouris
            read_permition=False, write_permition=False):
946 28470086 Stavros Sachtouris
        """Give read/write permisions to an object.
947 bc223d91 Stavros Sachtouris

948 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
949 bc223d91 Stavros Sachtouris

950 bc223d91 Stavros Sachtouris
        :param read_permition: (list - bool) users and user groups that get
951 bc223d91 Stavros Sachtouris
            read permition for this object - False means all previous read
952 bc223d91 Stavros Sachtouris
            permissions will be removed
953 bc223d91 Stavros Sachtouris

954 bc223d91 Stavros Sachtouris
        :param write_perimition: (list - bool) of users and user groups to get
955 bc223d91 Stavros Sachtouris
           write permition for this object - False means all previous write
956 4067cdaf Stavros Sachtouris
           permissions will be removed
957 28470086 Stavros Sachtouris
        """
958 4067cdaf Stavros Sachtouris
959 24ff0a35 Stavros Sachtouris
        perms = dict(
960 24ff0a35 Stavros Sachtouris
            read='' if not read_permition else read_permition,
961 3dabe5d2 Stavros Sachtouris
            write='' if not write_permition else write_permition)
962 bc223d91 Stavros Sachtouris
        r = self.object_post(obj, update=True, permissions=perms)
963 6ce9fc72 Stavros Sachtouris
        r.release()
964 28470086 Stavros Sachtouris
965 bc223d91 Stavros Sachtouris
    def del_object_sharing(self, obj):
966 bc223d91 Stavros Sachtouris
        """
967 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
968 bc223d91 Stavros Sachtouris
        """
969 bc223d91 Stavros Sachtouris
        self.set_object_sharing(obj)
970 bc223d91 Stavros Sachtouris
971 bc223d91 Stavros Sachtouris
    def append_object(self, obj, source_file, upload_cb=None):
972 bc223d91 Stavros Sachtouris
        """
973 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
974 bc223d91 Stavros Sachtouris

975 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
976 f49084df Stavros Sachtouris

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

1008 bc223d91 Stavros Sachtouris
        :param upto_bytes: max number of bytes to leave on file
1009 bc223d91 Stavros Sachtouris
        """
1010 24ff0a35 Stavros Sachtouris
        r = self.object_post(
1011 24ff0a35 Stavros Sachtouris
            obj,
1012 3dabe5d2 Stavros Sachtouris
            update=True,
1013 3dabe5d2 Stavros Sachtouris
            content_range='bytes 0-%s/*' % upto_bytes,
1014 3dabe5d2 Stavros Sachtouris
            content_type='application/octet-stream',
1015 3dabe5d2 Stavros Sachtouris
            object_bytes=upto_bytes,
1016 bc223d91 Stavros Sachtouris
            source_object=path4url(self.container, obj))
1017 6ce9fc72 Stavros Sachtouris
        r.release()
1018 ee62607e Stavros Sachtouris
1019 2005b18e Stavros Sachtouris
    def overwrite_object(self, obj, start, end, source_file, upload_cb=None):
1020 bc223d91 Stavros Sachtouris
        """Overwrite a part of an object from local source file
1021 bc223d91 Stavros Sachtouris

1022 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1023 bc223d91 Stavros Sachtouris

1024 bc223d91 Stavros Sachtouris
        :param start: (int) position in bytes to start overwriting from
1025 bc223d91 Stavros Sachtouris

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

1028 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
1029 bc223d91 Stavros Sachtouris

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

1081 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1082 bc223d91 Stavros Sachtouris

1083 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1084 bc223d91 Stavros Sachtouris

1085 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1086 bc223d91 Stavros Sachtouris

1087 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1088 bc223d91 Stavros Sachtouris

1089 bc223d91 Stavros Sachtouris
        :param public: (bool)
1090 bc223d91 Stavros Sachtouris

1091 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1092 bc223d91 Stavros Sachtouris

1093 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1094 bc223d91 Stavros Sachtouris
        """
1095 277ca4ed Dionysis Zindros
        self._assert_account()
1096 7d420701 Stavros Sachtouris
        self.container = dst_container
1097 7d420701 Stavros Sachtouris
        dst_object = dst_object or src_object
1098 7d420701 Stavros Sachtouris
        src_path = path4url(src_container, src_object)
1099 24ff0a35 Stavros Sachtouris
        r = self.object_put(
1100 24ff0a35 Stavros Sachtouris
            dst_object,
1101 3dabe5d2 Stavros Sachtouris
            success=201,
1102 3dabe5d2 Stavros Sachtouris
            copy_from=src_path,
1103 3dabe5d2 Stavros Sachtouris
            content_length=0,
1104 3dabe5d2 Stavros Sachtouris
            source_version=source_version,
1105 3dabe5d2 Stavros Sachtouris
            public=public,
1106 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
1107 7d420701 Stavros Sachtouris
            delimiter=delimiter)
1108 6ce9fc72 Stavros Sachtouris
        r.release()
1109 a5e0629d Stavros Sachtouris
1110 24ff0a35 Stavros Sachtouris
    def move_object(
1111 24ff0a35 Stavros Sachtouris
            self, src_container, src_object, dst_container,
1112 24ff0a35 Stavros Sachtouris
            dst_object=False,
1113 24ff0a35 Stavros Sachtouris
            source_version=None,
1114 24ff0a35 Stavros Sachtouris
            public=False,
1115 24ff0a35 Stavros Sachtouris
            content_type=None,
1116 24ff0a35 Stavros Sachtouris
            delimiter=None):
1117 bc223d91 Stavros Sachtouris
        """
1118 bc223d91 Stavros Sachtouris
        :param src_container: (str) source container
1119 bc223d91 Stavros Sachtouris

1120 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1121 bc223d91 Stavros Sachtouris

1122 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1123 bc223d91 Stavros Sachtouris

1124 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1125 bc223d91 Stavros Sachtouris

1126 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1127 bc223d91 Stavros Sachtouris

1128 bc223d91 Stavros Sachtouris
        :param public: (bool)
1129 bc223d91 Stavros Sachtouris

1130 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1131 bc223d91 Stavros Sachtouris

1132 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1133 bc223d91 Stavros Sachtouris
        """
1134 277ca4ed Dionysis Zindros
        self._assert_account()
1135 a5e0629d Stavros Sachtouris
        self.container = dst_container
1136 a5e0629d Stavros Sachtouris
        dst_object = dst_object or src_object
1137 a5e0629d Stavros Sachtouris
        src_path = path4url(src_container, src_object)
1138 24ff0a35 Stavros Sachtouris
        r = self.object_put(
1139 24ff0a35 Stavros Sachtouris
            dst_object,
1140 3dabe5d2 Stavros Sachtouris
            success=201,
1141 3dabe5d2 Stavros Sachtouris
            move_from=src_path,
1142 3dabe5d2 Stavros Sachtouris
            content_length=0,
1143 3dabe5d2 Stavros Sachtouris
            source_version=source_version,
1144 3dabe5d2 Stavros Sachtouris
            public=public,
1145 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
1146 a23f6ffe Stavros Sachtouris
            delimiter=delimiter)
1147 6ce9fc72 Stavros Sachtouris
        r.release()
1148 a23f6ffe Stavros Sachtouris
1149 a23f6ffe Stavros Sachtouris
    def get_sharing_accounts(self, limit=None, marker=None, *args, **kwargs):
1150 bc223d91 Stavros Sachtouris
        """Get accounts that share with self.account
1151 bc223d91 Stavros Sachtouris

1152 bc223d91 Stavros Sachtouris
        :param limit: (str)
1153 bc223d91 Stavros Sachtouris

1154 bc223d91 Stavros Sachtouris
        :param marker: (str)
1155 bc223d91 Stavros Sachtouris

1156 bc223d91 Stavros Sachtouris
        :returns: (dict)
1157 bc223d91 Stavros Sachtouris
        """
1158 277ca4ed Dionysis Zindros
        self._assert_account()
1159 a23f6ffe Stavros Sachtouris
1160 3dabe5d2 Stavros Sachtouris
        self.set_param('format', 'json')
1161 3dabe5d2 Stavros Sachtouris
        self.set_param('limit', limit, iff=limit is not None)
1162 3dabe5d2 Stavros Sachtouris
        self.set_param('marker', marker, iff=marker is not None)
1163 a23f6ffe Stavros Sachtouris
1164 a23f6ffe Stavros Sachtouris
        path = ''
1165 a23f6ffe Stavros Sachtouris
        success = kwargs.pop('success', (200, 204))
1166 3dabe5d2 Stavros Sachtouris
        r = self.get(path, *args, success=success, **kwargs)
1167 38dc5d2f Stavros Sachtouris
        return r.json
1168 38dc5d2f Stavros Sachtouris
1169 bc223d91 Stavros Sachtouris
    def get_object_versionlist(self, obj):
1170 bc223d91 Stavros Sachtouris
        """
1171 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1172 bc223d91 Stavros Sachtouris

1173 bc223d91 Stavros Sachtouris
        :returns: (list)
1174 bc223d91 Stavros Sachtouris
        """
1175 277ca4ed Dionysis Zindros
        self._assert_container()
1176 bc223d91 Stavros Sachtouris
        r = self.object_get(obj, format='json', version='list')
1177 38dc5d2f Stavros Sachtouris
        return r.json['versions']