Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / pithos / __init__.py @ 438efab2

History | View | Annotate | Download (49.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 49cc29b2 Stavros Sachtouris
from StringIO import StringIO
40 a91e0293 Giorgos Verigakis
41 64ab4c13 Stavros Sachtouris
from binascii import hexlify
42 6a0b1658 Giorgos Verigakis
43 6069b53b Stavros Sachtouris
from kamaki.clients import SilentEvent, sendlog
44 55faa0bc Stavros Sachtouris
from kamaki.clients.pithos.rest_api import PithosRestClient
45 c270fe96 Stavros Sachtouris
from kamaki.clients.storage import ClientError
46 4f228300 Stavros Sachtouris
from kamaki.clients.utils import path4url, filter_in, readall
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 776b275c Stavros Sachtouris
def _range_up(start, end, max_value, a_range):
56 776b275c Stavros Sachtouris
    """
57 776b275c Stavros Sachtouris
    :param start: (int) the window bottom
58 776b275c Stavros Sachtouris

59 776b275c Stavros Sachtouris
    :param end: (int) the window top
60 776b275c Stavros Sachtouris

61 776b275c Stavros Sachtouris
    :param max_value: (int) maximum accepted value
62 776b275c Stavros Sachtouris

63 776b275c Stavros Sachtouris
    :param a_range: (str) a range string in the form X[,X'[,X''[...]]]
64 776b275c Stavros Sachtouris
        where X: x|x-y|-x where x < y and x, y natural numbers
65 776b275c Stavros Sachtouris

66 776b275c Stavros Sachtouris
    :returns: (str) a range string cut-off for the start-end range
67 776b275c Stavros Sachtouris
        an empty response means this window is out of range
68 776b275c Stavros Sachtouris
    """
69 bd02c3ea Stavros Sachtouris
    assert start >= 0, '_range_up called w. start(%s) < 0' % start
70 bd02c3ea Stavros Sachtouris
    assert end >= start, '_range_up called w. end(%s) < start(%s)' % (
71 bd02c3ea Stavros Sachtouris
        end, start)
72 bd02c3ea Stavros Sachtouris
    assert end <= max_value, '_range_up called w. max_value(%s) < end(%s)' % (
73 bd02c3ea Stavros Sachtouris
        max_value, end)
74 776b275c Stavros Sachtouris
    if not a_range:
75 776b275c Stavros Sachtouris
        return '%s-%s' % (start, end)
76 776b275c Stavros Sachtouris
    selected = []
77 776b275c Stavros Sachtouris
    for some_range in a_range.split(','):
78 776b275c Stavros Sachtouris
        v0, sep, v1 = some_range.partition('-')
79 776b275c Stavros Sachtouris
        if v0:
80 776b275c Stavros Sachtouris
            v0 = int(v0)
81 6e50fed4 Stavros Sachtouris
            if sep:
82 776b275c Stavros Sachtouris
                v1 = int(v1)
83 776b275c Stavros Sachtouris
                if v1 < start or v0 > end or v1 < v0:
84 776b275c Stavros Sachtouris
                    continue
85 776b275c Stavros Sachtouris
                v0 = v0 if v0 > start else start
86 776b275c Stavros Sachtouris
                v1 = v1 if v1 < end else end
87 776b275c Stavros Sachtouris
                selected.append('%s-%s' % (v0, v1))
88 776b275c Stavros Sachtouris
            elif v0 < start:
89 776b275c Stavros Sachtouris
                continue
90 6e50fed4 Stavros Sachtouris
            else:
91 776b275c Stavros Sachtouris
                v1 = v0 if v0 <= end else end
92 776b275c Stavros Sachtouris
                selected.append('%s-%s' % (start, v1))
93 6e50fed4 Stavros Sachtouris
        else:
94 776b275c Stavros Sachtouris
            v1 = int(v1)
95 776b275c Stavros Sachtouris
            if max_value - v1 > end:
96 776b275c Stavros Sachtouris
                continue
97 776b275c Stavros Sachtouris
            v0 = (max_value - v1) if max_value - v1 > start else start
98 776b275c Stavros Sachtouris
            selected.append('%s-%s' % (v0, end))
99 776b275c Stavros Sachtouris
    return ','.join(selected)
100 642f1bbd Stavros Sachtouris
101 3dabe5d2 Stavros Sachtouris
102 55faa0bc Stavros Sachtouris
class PithosClient(PithosRestClient):
103 76e7661e Stavros Sachtouris
    """Synnefo Pithos+ API client"""
104 a91e0293 Giorgos Verigakis
105 3dabe5d2 Stavros Sachtouris
    def __init__(self, base_url, token, account=None, container=None):
106 3dabe5d2 Stavros Sachtouris
        super(PithosClient, self).__init__(base_url, token, account, container)
107 435008b6 Stavros Sachtouris
108 94bedc5b Stavros Sachtouris
    def create_container(
109 94bedc5b Stavros Sachtouris
            self,
110 6c068db6 Stavros Sachtouris
            container=None, sizelimit=None, versioning=None, metadata=None,
111 6c068db6 Stavros Sachtouris
            **kwargs):
112 94bedc5b Stavros Sachtouris
        """
113 94bedc5b Stavros Sachtouris
        :param container: (str) if not given, self.container is used instead
114 94bedc5b Stavros Sachtouris

115 94bedc5b Stavros Sachtouris
        :param sizelimit: (int) container total size limit in bytes
116 94bedc5b Stavros Sachtouris

117 94bedc5b Stavros Sachtouris
        :param versioning: (str) can be auto or whatever supported by server
118 94bedc5b Stavros Sachtouris

119 94bedc5b Stavros Sachtouris
        :param metadata: (dict) Custom user-defined metadata of the form
120 94bedc5b Stavros Sachtouris
            { 'name1': 'value1', 'name2': 'value2', ... }
121 94bedc5b Stavros Sachtouris

122 94bedc5b Stavros Sachtouris
        :returns: (dict) response headers
123 94bedc5b Stavros Sachtouris
        """
124 94bedc5b Stavros Sachtouris
        cnt_back_up = self.container
125 94bedc5b Stavros Sachtouris
        try:
126 94bedc5b Stavros Sachtouris
            self.container = container or cnt_back_up
127 94bedc5b Stavros Sachtouris
            r = self.container_put(
128 6c068db6 Stavros Sachtouris
                quota=sizelimit, versioning=versioning, metadata=metadata,
129 6c068db6 Stavros Sachtouris
                **kwargs)
130 94bedc5b Stavros Sachtouris
            return r.headers
131 94bedc5b Stavros Sachtouris
        finally:
132 94bedc5b Stavros Sachtouris
            self.container = cnt_back_up
133 94bedc5b Stavros Sachtouris
134 2a7292f1 Stavros Sachtouris
    def purge_container(self, container=None):
135 4375e020 Stavros Sachtouris
        """Delete an empty container and destroy associated blocks
136 4375e020 Stavros Sachtouris
        """
137 2a7292f1 Stavros Sachtouris
        cnt_back_up = self.container
138 2a7292f1 Stavros Sachtouris
        try:
139 2a7292f1 Stavros Sachtouris
            self.container = container or cnt_back_up
140 5655d560 Stavros Sachtouris
            r = self.container_delete(until=unicode(time()))
141 2a7292f1 Stavros Sachtouris
        finally:
142 2a7292f1 Stavros Sachtouris
            self.container = cnt_back_up
143 5655d560 Stavros Sachtouris
        return r.headers
144 3dabe5d2 Stavros Sachtouris
145 24ff0a35 Stavros Sachtouris
    def upload_object_unchunked(
146 24ff0a35 Stavros Sachtouris
            self, obj, f,
147 24ff0a35 Stavros Sachtouris
            withHashFile=False,
148 24ff0a35 Stavros Sachtouris
            size=None,
149 24ff0a35 Stavros Sachtouris
            etag=None,
150 24ff0a35 Stavros Sachtouris
            content_encoding=None,
151 24ff0a35 Stavros Sachtouris
            content_disposition=None,
152 24ff0a35 Stavros Sachtouris
            content_type=None,
153 24ff0a35 Stavros Sachtouris
            sharing=None,
154 24ff0a35 Stavros Sachtouris
            public=None):
155 4375e020 Stavros Sachtouris
        """
156 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
157 4375e020 Stavros Sachtouris

158 4375e020 Stavros Sachtouris
        :param f: open file descriptor
159 4375e020 Stavros Sachtouris

160 4375e020 Stavros Sachtouris
        :param withHashFile: (bool)
161 4375e020 Stavros Sachtouris

162 4375e020 Stavros Sachtouris
        :param size: (int) size of data to upload
163 4375e020 Stavros Sachtouris

164 4375e020 Stavros Sachtouris
        :param etag: (str)
165 4375e020 Stavros Sachtouris

166 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
167 4375e020 Stavros Sachtouris

168 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
169 4375e020 Stavros Sachtouris

170 4375e020 Stavros Sachtouris
        :param content_type: (str)
171 4375e020 Stavros Sachtouris

172 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
173 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
174 4375e020 Stavros Sachtouris

175 4375e020 Stavros Sachtouris
        :param public: (bool)
176 3c216009 Stavros Sachtouris

177 3c216009 Stavros Sachtouris
        :returns: (dict) created object metadata
178 4375e020 Stavros Sachtouris
        """
179 277ca4ed Dionysis Zindros
        self._assert_container()
180 65a45524 Stavros Sachtouris
181 65a45524 Stavros Sachtouris
        if withHashFile:
182 65a45524 Stavros Sachtouris
            data = f.read()
183 65a45524 Stavros Sachtouris
            try:
184 65a45524 Stavros Sachtouris
                import json
185 65a45524 Stavros Sachtouris
                data = json.dumps(json.loads(data))
186 65a45524 Stavros Sachtouris
            except ValueError:
187 24ff0a35 Stavros Sachtouris
                raise ClientError('"%s" is not json-formated' % f.name, 1)
188 65a45524 Stavros Sachtouris
            except SyntaxError:
189 24ff0a35 Stavros Sachtouris
                msg = '"%s" is not a valid hashmap file' % f.name
190 24ff0a35 Stavros Sachtouris
                raise ClientError(msg, 1)
191 65a45524 Stavros Sachtouris
            f = StringIO(data)
192 2a7292f1 Stavros Sachtouris
        else:
193 4f228300 Stavros Sachtouris
            data = readall(f, size) if size else f.read()
194 3c216009 Stavros Sachtouris
        r = self.object_put(
195 24ff0a35 Stavros Sachtouris
            obj,
196 3dabe5d2 Stavros Sachtouris
            data=data,
197 3dabe5d2 Stavros Sachtouris
            etag=etag,
198 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
199 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
200 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
201 3dabe5d2 Stavros Sachtouris
            permissions=sharing,
202 3dabe5d2 Stavros Sachtouris
            public=public,
203 3dabe5d2 Stavros Sachtouris
            success=201)
204 3c216009 Stavros Sachtouris
        return r.headers
205 3dabe5d2 Stavros Sachtouris
206 24ff0a35 Stavros Sachtouris
    def create_object_by_manifestation(
207 24ff0a35 Stavros Sachtouris
            self, obj,
208 24ff0a35 Stavros Sachtouris
            etag=None,
209 24ff0a35 Stavros Sachtouris
            content_encoding=None,
210 24ff0a35 Stavros Sachtouris
            content_disposition=None,
211 24ff0a35 Stavros Sachtouris
            content_type=None,
212 24ff0a35 Stavros Sachtouris
            sharing=None,
213 24ff0a35 Stavros Sachtouris
            public=None):
214 4375e020 Stavros Sachtouris
        """
215 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
216 4375e020 Stavros Sachtouris

217 4375e020 Stavros Sachtouris
        :param etag: (str)
218 4375e020 Stavros Sachtouris

219 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
220 4375e020 Stavros Sachtouris

221 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
222 4375e020 Stavros Sachtouris

223 4375e020 Stavros Sachtouris
        :param content_type: (str)
224 4375e020 Stavros Sachtouris

225 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
226 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
227 4375e020 Stavros Sachtouris

228 4375e020 Stavros Sachtouris
        :param public: (bool)
229 3c216009 Stavros Sachtouris

230 3c216009 Stavros Sachtouris
        :returns: (dict) created object metadata
231 4375e020 Stavros Sachtouris
        """
232 277ca4ed Dionysis Zindros
        self._assert_container()
233 3c216009 Stavros Sachtouris
        r = self.object_put(
234 24ff0a35 Stavros Sachtouris
            obj,
235 3dabe5d2 Stavros Sachtouris
            content_length=0,
236 3dabe5d2 Stavros Sachtouris
            etag=etag,
237 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
238 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
239 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
240 3dabe5d2 Stavros Sachtouris
            permissions=sharing,
241 3dabe5d2 Stavros Sachtouris
            public=public,
242 3dabe5d2 Stavros Sachtouris
            manifest='%s/%s' % (self.container, obj))
243 3c216009 Stavros Sachtouris
        return r.headers
244 3dabe5d2 Stavros Sachtouris
245 4375e020 Stavros Sachtouris
    # upload_* auxiliary methods
246 9d502497 Stavros Sachtouris
    def _put_block_async(self, data, hash):
247 4375e020 Stavros Sachtouris
        event = SilentEvent(method=self._put_block, data=data, hash=hash)
248 4375e020 Stavros Sachtouris
        event.start()
249 4375e020 Stavros Sachtouris
        return event
250 4375e020 Stavros Sachtouris
251 4375e020 Stavros Sachtouris
    def _put_block(self, data, hash):
252 24ff0a35 Stavros Sachtouris
        r = self.container_post(
253 24ff0a35 Stavros Sachtouris
            update=True,
254 4375e020 Stavros Sachtouris
            content_type='application/octet-stream',
255 4375e020 Stavros Sachtouris
            content_length=len(data),
256 4375e020 Stavros Sachtouris
            data=data,
257 4375e020 Stavros Sachtouris
            format='json')
258 4375e020 Stavros Sachtouris
        assert r.json[0] == hash, 'Local hash does not match server'
259 4375e020 Stavros Sachtouris
260 76ebf97c Stavros Sachtouris
    def _get_file_block_info(self, fileobj, size=None, cache=None):
261 76ebf97c Stavros Sachtouris
        """
262 76ebf97c Stavros Sachtouris
        :param fileobj: (file descriptor) source
263 76ebf97c Stavros Sachtouris

264 76ebf97c Stavros Sachtouris
        :param size: (int) size of data to upload from source
265 76ebf97c Stavros Sachtouris

266 76ebf97c Stavros Sachtouris
        :param cache: (dict) if provided, cache container info response to
267 76ebf97c Stavros Sachtouris
        avoid redundant calls
268 76ebf97c Stavros Sachtouris
        """
269 76ebf97c Stavros Sachtouris
        if isinstance(cache, dict):
270 76ebf97c Stavros Sachtouris
            try:
271 76ebf97c Stavros Sachtouris
                meta = cache[self.container]
272 76ebf97c Stavros Sachtouris
            except KeyError:
273 76ebf97c Stavros Sachtouris
                meta = self.get_container_info()
274 76ebf97c Stavros Sachtouris
                cache[self.container] = meta
275 76ebf97c Stavros Sachtouris
        else:
276 76ebf97c Stavros Sachtouris
            meta = self.get_container_info()
277 435008b6 Stavros Sachtouris
        blocksize = int(meta['x-container-block-size'])
278 435008b6 Stavros Sachtouris
        blockhash = meta['x-container-block-hash']
279 64ab4c13 Stavros Sachtouris
        size = size if size is not None else fstat(fileobj.fileno()).st_size
280 435008b6 Stavros Sachtouris
        nblocks = 1 + (size - 1) // blocksize
281 64ab4c13 Stavros Sachtouris
        return (blocksize, blockhash, size, nblocks)
282 64ab4c13 Stavros Sachtouris
283 9d502497 Stavros Sachtouris
    def _create_object_or_get_missing_hashes(
284 24ff0a35 Stavros Sachtouris
            self, obj, json,
285 24ff0a35 Stavros Sachtouris
            size=None,
286 24ff0a35 Stavros Sachtouris
            format='json',
287 24ff0a35 Stavros Sachtouris
            hashmap=True,
288 24ff0a35 Stavros Sachtouris
            content_type=None,
289 b349b84b Stavros Sachtouris
            if_etag_match=None,
290 b349b84b Stavros Sachtouris
            if_etag_not_match=None,
291 24ff0a35 Stavros Sachtouris
            content_encoding=None,
292 24ff0a35 Stavros Sachtouris
            content_disposition=None,
293 24ff0a35 Stavros Sachtouris
            permissions=None,
294 24ff0a35 Stavros Sachtouris
            public=None,
295 24ff0a35 Stavros Sachtouris
            success=(201, 409)):
296 24ff0a35 Stavros Sachtouris
        r = self.object_put(
297 24ff0a35 Stavros Sachtouris
            obj,
298 3dabe5d2 Stavros Sachtouris
            format='json',
299 3dabe5d2 Stavros Sachtouris
            hashmap=True,
300 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
301 3dabe5d2 Stavros Sachtouris
            json=json,
302 b349b84b Stavros Sachtouris
            if_etag_match=if_etag_match,
303 b349b84b Stavros Sachtouris
            if_etag_not_match=if_etag_not_match,
304 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
305 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
306 3dabe5d2 Stavros Sachtouris
            permissions=permissions,
307 3dabe5d2 Stavros Sachtouris
            public=public,
308 64ab4c13 Stavros Sachtouris
            success=success)
309 3c216009 Stavros Sachtouris
        return (None if r.status_code == 201 else r.json), r.headers
310 435008b6 Stavros Sachtouris
311 b349b84b Stavros Sachtouris
    def _calculate_blocks_for_upload(
312 2005b18e Stavros Sachtouris
            self, blocksize, blockhash, size, nblocks, hashes, hmap, fileobj,
313 2005b18e Stavros Sachtouris
            hash_cb=None):
314 3dabe5d2 Stavros Sachtouris
        offset = 0
315 435008b6 Stavros Sachtouris
        if hash_cb:
316 435008b6 Stavros Sachtouris
            hash_gen = hash_cb(nblocks)
317 435008b6 Stavros Sachtouris
            hash_gen.next()
318 435008b6 Stavros Sachtouris
319 435008b6 Stavros Sachtouris
        for i in range(nblocks):
320 4f228300 Stavros Sachtouris
            block = readall(fileobj, min(blocksize, size - offset))
321 435008b6 Stavros Sachtouris
            bytes = len(block)
322 4375e020 Stavros Sachtouris
            hash = _pithos_hash(block, blockhash)
323 435008b6 Stavros Sachtouris
            hashes.append(hash)
324 5b263ba2 Stavros Sachtouris
            hmap[hash] = (offset, bytes)
325 435008b6 Stavros Sachtouris
            offset += bytes
326 435008b6 Stavros Sachtouris
            if hash_cb:
327 435008b6 Stavros Sachtouris
                hash_gen.next()
328 ab863157 Stavros Sachtouris
        msg = ('Failed to calculate uploaded blocks:'
329 ab863157 Stavros Sachtouris
               ' Offset and object size do not match')
330 fce31e83 Stavros Sachtouris
        assert offset == size, msg
331 435008b6 Stavros Sachtouris
332 3e7d1e0e Stavros Sachtouris
    def _upload_missing_blocks(self, missing, hmap, fileobj, upload_gen=None):
333 3e7d1e0e Stavros Sachtouris
        """upload missing blocks asynchronously"""
334 435008b6 Stavros Sachtouris
335 cad39033 Stavros Sachtouris
        self._init_thread_limit()
336 e9abe82b Stavros Sachtouris
337 435008b6 Stavros Sachtouris
        flying = []
338 7644c38e Stavros Sachtouris
        failures = []
339 435008b6 Stavros Sachtouris
        for hash in missing:
340 5b263ba2 Stavros Sachtouris
            offset, bytes = hmap[hash]
341 64ab4c13 Stavros Sachtouris
            fileobj.seek(offset)
342 4f228300 Stavros Sachtouris
            data = readall(fileobj, bytes)
343 9d502497 Stavros Sachtouris
            r = self._put_block_async(data, hash)
344 435008b6 Stavros Sachtouris
            flying.append(r)
345 745d938b Stavros Sachtouris
            unfinished = self._watch_thread_limit(flying)
346 745d938b Stavros Sachtouris
            for thread in set(flying).difference(unfinished):
347 7644c38e Stavros Sachtouris
                if thread.exception:
348 7644c38e Stavros Sachtouris
                    failures.append(thread)
349 24ff0a35 Stavros Sachtouris
                    if isinstance(
350 2005b18e Stavros Sachtouris
                            thread.exception,
351 2005b18e Stavros Sachtouris
                            ClientError) and thread.exception.status == 502:
352 2005b18e Stavros Sachtouris
                        self.POOLSIZE = self._thread_limit
353 7644c38e Stavros Sachtouris
                elif thread.isAlive():
354 745d938b Stavros Sachtouris
                    flying.append(thread)
355 3e7d1e0e Stavros Sachtouris
                elif upload_gen:
356 3e7d1e0e Stavros Sachtouris
                    try:
357 3e7d1e0e Stavros Sachtouris
                        upload_gen.next()
358 3e7d1e0e Stavros Sachtouris
                    except:
359 3e7d1e0e Stavros Sachtouris
                        pass
360 e02728f9 Stavros Sachtouris
            flying = unfinished
361 e02728f9 Stavros Sachtouris
362 e02728f9 Stavros Sachtouris
        for thread in flying:
363 e02728f9 Stavros Sachtouris
            thread.join()
364 7644c38e Stavros Sachtouris
            if thread.exception:
365 7644c38e Stavros Sachtouris
                failures.append(thread)
366 3e7d1e0e Stavros Sachtouris
            elif upload_gen:
367 3e7d1e0e Stavros Sachtouris
                try:
368 3e7d1e0e Stavros Sachtouris
                    upload_gen.next()
369 3e7d1e0e Stavros Sachtouris
                except:
370 3e7d1e0e Stavros Sachtouris
                    pass
371 56f0908a Stavros Sachtouris
372 7644c38e Stavros Sachtouris
        return [failure.kwargs['hash'] for failure in failures]
373 3dabe5d2 Stavros Sachtouris
374 24ff0a35 Stavros Sachtouris
    def upload_object(
375 24ff0a35 Stavros Sachtouris
            self, obj, f,
376 24ff0a35 Stavros Sachtouris
            size=None,
377 24ff0a35 Stavros Sachtouris
            hash_cb=None,
378 24ff0a35 Stavros Sachtouris
            upload_cb=None,
379 24ff0a35 Stavros Sachtouris
            etag=None,
380 e9ac514e Stavros Sachtouris
            if_etag_match=None,
381 524d9cdd Stavros Sachtouris
            if_not_exist=None,
382 24ff0a35 Stavros Sachtouris
            content_encoding=None,
383 24ff0a35 Stavros Sachtouris
            content_disposition=None,
384 24ff0a35 Stavros Sachtouris
            content_type=None,
385 24ff0a35 Stavros Sachtouris
            sharing=None,
386 76ebf97c Stavros Sachtouris
            public=None,
387 76ebf97c Stavros Sachtouris
            container_info_cache=None):
388 4375e020 Stavros Sachtouris
        """Upload an object using multiple connections (threads)
389 4375e020 Stavros Sachtouris

390 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
391 4375e020 Stavros Sachtouris

392 4375e020 Stavros Sachtouris
        :param f: open file descriptor (rb)
393 4375e020 Stavros Sachtouris

394 4375e020 Stavros Sachtouris
        :param hash_cb: optional progress.bar object for calculating hashes
395 4375e020 Stavros Sachtouris

396 4375e020 Stavros Sachtouris
        :param upload_cb: optional progress.bar object for uploading
397 4375e020 Stavros Sachtouris

398 4375e020 Stavros Sachtouris
        :param etag: (str)
399 4375e020 Stavros Sachtouris

400 e9ac514e Stavros Sachtouris
        :param if_etag_match: (str) Push that value to if-match header at file
401 e9ac514e Stavros Sachtouris
            creation
402 e9ac514e Stavros Sachtouris

403 524d9cdd Stavros Sachtouris
        :param if_not_exist: (bool) If true, the file will be uploaded ONLY if
404 524d9cdd Stavros Sachtouris
            it does not exist remotely, otherwise the operation will fail.
405 524d9cdd Stavros Sachtouris
            Involves the case of an object with the same path is created while
406 524d9cdd Stavros Sachtouris
            the object is being uploaded.
407 524d9cdd Stavros Sachtouris

408 4375e020 Stavros Sachtouris
        :param content_encoding: (str)
409 4375e020 Stavros Sachtouris

410 4375e020 Stavros Sachtouris
        :param content_disposition: (str)
411 4375e020 Stavros Sachtouris

412 4375e020 Stavros Sachtouris
        :param content_type: (str)
413 4375e020 Stavros Sachtouris

414 4375e020 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
415 4375e020 Stavros Sachtouris
            'write':[usr and/or grp names]}
416 4375e020 Stavros Sachtouris

417 4375e020 Stavros Sachtouris
        :param public: (bool)
418 76ebf97c Stavros Sachtouris

419 76ebf97c Stavros Sachtouris
        :param container_info_cache: (dict) if given, avoid redundant calls to
420 9dc6159f Stavros Sachtouris
            server for container info (block size and hash information)
421 4375e020 Stavros Sachtouris
        """
422 277ca4ed Dionysis Zindros
        self._assert_container()
423 56f0908a Stavros Sachtouris
424 14c72dbd Stavros Sachtouris
        block_info = (
425 14c72dbd Stavros Sachtouris
            blocksize, blockhash, size, nblocks) = self._get_file_block_info(
426 14c72dbd Stavros Sachtouris
                f, size, container_info_cache)
427 64ab4c13 Stavros Sachtouris
        (hashes, hmap, offset) = ([], {}, 0)
428 bcbf3cf0 Stavros Sachtouris
        if not content_type:
429 3dabe5d2 Stavros Sachtouris
            content_type = 'application/octet-stream'
430 64ab4c13 Stavros Sachtouris
431 b349b84b Stavros Sachtouris
        self._calculate_blocks_for_upload(
432 24ff0a35 Stavros Sachtouris
            *block_info,
433 3dabe5d2 Stavros Sachtouris
            hashes=hashes,
434 3dabe5d2 Stavros Sachtouris
            hmap=hmap,
435 3dabe5d2 Stavros Sachtouris
            fileobj=f,
436 64ab4c13 Stavros Sachtouris
            hash_cb=hash_cb)
437 64ab4c13 Stavros Sachtouris
438 64ab4c13 Stavros Sachtouris
        hashmap = dict(bytes=size, hashes=hashes)
439 9d502497 Stavros Sachtouris
        missing, obj_headers = self._create_object_or_get_missing_hashes(
440 24ff0a35 Stavros Sachtouris
            obj, hashmap,
441 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
442 3dabe5d2 Stavros Sachtouris
            size=size,
443 b349b84b Stavros Sachtouris
            if_etag_match=if_etag_match,
444 b349b84b Stavros Sachtouris
            if_etag_not_match='*' if if_not_exist else None,
445 3dabe5d2 Stavros Sachtouris
            content_encoding=content_encoding,
446 3dabe5d2 Stavros Sachtouris
            content_disposition=content_disposition,
447 3dabe5d2 Stavros Sachtouris
            permissions=sharing,
448 3dabe5d2 Stavros Sachtouris
            public=public)
449 64ab4c13 Stavros Sachtouris
450 64ab4c13 Stavros Sachtouris
        if missing is None:
451 3c216009 Stavros Sachtouris
            return obj_headers
452 1d329d27 Stavros Sachtouris
453 3e7d1e0e Stavros Sachtouris
        if upload_cb:
454 3e7d1e0e Stavros Sachtouris
            upload_gen = upload_cb(len(missing))
455 745d938b Stavros Sachtouris
            for i in range(len(missing), len(hashmap['hashes']) + 1):
456 745d938b Stavros Sachtouris
                try:
457 745d938b Stavros Sachtouris
                    upload_gen.next()
458 745d938b Stavros Sachtouris
                except:
459 745d938b Stavros Sachtouris
                    upload_gen = None
460 3e7d1e0e Stavros Sachtouris
        else:
461 3e7d1e0e Stavros Sachtouris
            upload_gen = None
462 3e7d1e0e Stavros Sachtouris
463 7eda693f Stavros Sachtouris
        retries = 7
464 f27ed9a0 Stavros Sachtouris
        try:
465 7644c38e Stavros Sachtouris
            while retries:
466 7eda693f Stavros Sachtouris
                sendlog.info('%s blocks missing' % len(missing))
467 7644c38e Stavros Sachtouris
                num_of_blocks = len(missing)
468 7644c38e Stavros Sachtouris
                missing = self._upload_missing_blocks(
469 7644c38e Stavros Sachtouris
                    missing,
470 7644c38e Stavros Sachtouris
                    hmap,
471 7644c38e Stavros Sachtouris
                    f,
472 3e7d1e0e Stavros Sachtouris
                    upload_gen)
473 16c895db Stavros Sachtouris
                if missing:
474 16c895db Stavros Sachtouris
                    if num_of_blocks == len(missing):
475 16c895db Stavros Sachtouris
                        retries -= 1
476 16c895db Stavros Sachtouris
                    else:
477 16c895db Stavros Sachtouris
                        num_of_blocks = len(missing)
478 7644c38e Stavros Sachtouris
                else:
479 7644c38e Stavros Sachtouris
                    break
480 7644c38e Stavros Sachtouris
            if missing:
481 ecf0fc97 Stavros Sachtouris
                try:
482 ecf0fc97 Stavros Sachtouris
                    details = ['%s' % thread.exception for thread in missing]
483 ecf0fc97 Stavros Sachtouris
                except Exception:
484 5c2058e7 Stavros Sachtouris
                    details = ['Also, failed to read thread exceptions']
485 6fa30b1b Stavros Sachtouris
                raise ClientError(
486 6fa30b1b Stavros Sachtouris
                    '%s blocks failed to upload' % len(missing),
487 ecf0fc97 Stavros Sachtouris
                    details=details)
488 9d502497 Stavros Sachtouris
        except KeyboardInterrupt:
489 9d502497 Stavros Sachtouris
            sendlog.info('- - - wait for threads to finish')
490 9d502497 Stavros Sachtouris
            for thread in activethreads():
491 9d502497 Stavros Sachtouris
                thread.join()
492 9d502497 Stavros Sachtouris
            raise
493 9d502497 Stavros Sachtouris
494 9d502497 Stavros Sachtouris
        r = self.object_put(
495 9d502497 Stavros Sachtouris
            obj,
496 9d502497 Stavros Sachtouris
            format='json',
497 9d502497 Stavros Sachtouris
            hashmap=True,
498 9d502497 Stavros Sachtouris
            content_type=content_type,
499 f8426b5c Stavros Sachtouris
            content_encoding=content_encoding,
500 9d502497 Stavros Sachtouris
            if_etag_match=if_etag_match,
501 9d502497 Stavros Sachtouris
            if_etag_not_match='*' if if_not_exist else None,
502 9d502497 Stavros Sachtouris
            etag=etag,
503 9d502497 Stavros Sachtouris
            json=hashmap,
504 9d502497 Stavros Sachtouris
            permissions=sharing,
505 9d502497 Stavros Sachtouris
            public=public,
506 9d502497 Stavros Sachtouris
            success=201)
507 9d502497 Stavros Sachtouris
        return r.headers
508 9d502497 Stavros Sachtouris
509 9d502497 Stavros Sachtouris
    def upload_from_string(
510 9d502497 Stavros Sachtouris
            self, obj, input_str,
511 9d502497 Stavros Sachtouris
            hash_cb=None,
512 9d502497 Stavros Sachtouris
            upload_cb=None,
513 9d502497 Stavros Sachtouris
            etag=None,
514 9d502497 Stavros Sachtouris
            if_etag_match=None,
515 9d502497 Stavros Sachtouris
            if_not_exist=None,
516 9d502497 Stavros Sachtouris
            content_encoding=None,
517 9d502497 Stavros Sachtouris
            content_disposition=None,
518 9d502497 Stavros Sachtouris
            content_type=None,
519 9d502497 Stavros Sachtouris
            sharing=None,
520 9d502497 Stavros Sachtouris
            public=None,
521 9d502497 Stavros Sachtouris
            container_info_cache=None):
522 9d502497 Stavros Sachtouris
        """Upload an object using multiple connections (threads)
523 9d502497 Stavros Sachtouris

524 9d502497 Stavros Sachtouris
        :param obj: (str) remote object path
525 9d502497 Stavros Sachtouris

526 9d502497 Stavros Sachtouris
        :param input_str: (str) upload content
527 9d502497 Stavros Sachtouris

528 9d502497 Stavros Sachtouris
        :param hash_cb: optional progress.bar object for calculating hashes
529 9d502497 Stavros Sachtouris

530 9d502497 Stavros Sachtouris
        :param upload_cb: optional progress.bar object for uploading
531 9d502497 Stavros Sachtouris

532 9d502497 Stavros Sachtouris
        :param etag: (str)
533 9d502497 Stavros Sachtouris

534 9d502497 Stavros Sachtouris
        :param if_etag_match: (str) Push that value to if-match header at file
535 9d502497 Stavros Sachtouris
            creation
536 9d502497 Stavros Sachtouris

537 9d502497 Stavros Sachtouris
        :param if_not_exist: (bool) If true, the file will be uploaded ONLY if
538 9d502497 Stavros Sachtouris
            it does not exist remotely, otherwise the operation will fail.
539 9d502497 Stavros Sachtouris
            Involves the case of an object with the same path is created while
540 9d502497 Stavros Sachtouris
            the object is being uploaded.
541 9d502497 Stavros Sachtouris

542 9d502497 Stavros Sachtouris
        :param content_encoding: (str)
543 9d502497 Stavros Sachtouris

544 9d502497 Stavros Sachtouris
        :param content_disposition: (str)
545 9d502497 Stavros Sachtouris

546 9d502497 Stavros Sachtouris
        :param content_type: (str)
547 9d502497 Stavros Sachtouris

548 9d502497 Stavros Sachtouris
        :param sharing: {'read':[user and/or grp names],
549 9d502497 Stavros Sachtouris
            'write':[usr and/or grp names]}
550 9d502497 Stavros Sachtouris

551 9d502497 Stavros Sachtouris
        :param public: (bool)
552 9d502497 Stavros Sachtouris

553 9d502497 Stavros Sachtouris
        :param container_info_cache: (dict) if given, avoid redundant calls to
554 9dc6159f Stavros Sachtouris
            server for container info (block size and hash information)
555 9d502497 Stavros Sachtouris
        """
556 9d502497 Stavros Sachtouris
        self._assert_container()
557 9d502497 Stavros Sachtouris
558 9d502497 Stavros Sachtouris
        blocksize, blockhash, size, nblocks = self._get_file_block_info(
559 9d502497 Stavros Sachtouris
                fileobj=None, size=len(input_str), cache=container_info_cache)
560 9d502497 Stavros Sachtouris
        (hashes, hmap, offset) = ([], {}, 0)
561 9d502497 Stavros Sachtouris
        if not content_type:
562 9d502497 Stavros Sachtouris
            content_type = 'application/octet-stream'
563 9d502497 Stavros Sachtouris
564 6fa30b1b Stavros Sachtouris
        hashes = []
565 9d502497 Stavros Sachtouris
        hmap = {}
566 f17121cd Stavros Sachtouris
        for blockid in range(nblocks):
567 9d502497 Stavros Sachtouris
            start = blockid * blocksize
568 9d502497 Stavros Sachtouris
            block = input_str[start: (start + blocksize)]
569 6fa30b1b Stavros Sachtouris
            hashes.append(_pithos_hash(block, blockhash))
570 9d502497 Stavros Sachtouris
            hmap[hashes[blockid]] = (start, block)
571 9d502497 Stavros Sachtouris
572 9d502497 Stavros Sachtouris
        hashmap = dict(bytes=size, hashes=hashes)
573 9d502497 Stavros Sachtouris
        missing, obj_headers = self._create_object_or_get_missing_hashes(
574 9d502497 Stavros Sachtouris
            obj, hashmap,
575 9d502497 Stavros Sachtouris
            content_type=content_type,
576 9d502497 Stavros Sachtouris
            size=size,
577 9d502497 Stavros Sachtouris
            if_etag_match=if_etag_match,
578 9d502497 Stavros Sachtouris
            if_etag_not_match='*' if if_not_exist else None,
579 9d502497 Stavros Sachtouris
            content_encoding=content_encoding,
580 9d502497 Stavros Sachtouris
            content_disposition=content_disposition,
581 9d502497 Stavros Sachtouris
            permissions=sharing,
582 9d502497 Stavros Sachtouris
            public=public)
583 9d502497 Stavros Sachtouris
        if missing is None:
584 9d502497 Stavros Sachtouris
            return obj_headers
585 9d502497 Stavros Sachtouris
        num_of_missing = len(missing)
586 9d502497 Stavros Sachtouris
587 9d502497 Stavros Sachtouris
        if upload_cb:
588 f17121cd Stavros Sachtouris
            self.progress_bar_gen = upload_cb(nblocks)
589 f17121cd Stavros Sachtouris
            for i in range(nblocks + 1 - num_of_missing):
590 9d502497 Stavros Sachtouris
                self._cb_next()
591 9d502497 Stavros Sachtouris
592 6fa30b1b Stavros Sachtouris
        tries = 7
593 6fa30b1b Stavros Sachtouris
        old_failures = 0
594 9d502497 Stavros Sachtouris
        try:
595 6fa30b1b Stavros Sachtouris
            while tries and missing:
596 6fa30b1b Stavros Sachtouris
                flying = []
597 6fa30b1b Stavros Sachtouris
                failures = []
598 6fa30b1b Stavros Sachtouris
                for hash in missing:
599 6fa30b1b Stavros Sachtouris
                    offset, block = hmap[hash]
600 6fa30b1b Stavros Sachtouris
                    bird = self._put_block_async(block, hash)
601 6fa30b1b Stavros Sachtouris
                    flying.append(bird)
602 6fa30b1b Stavros Sachtouris
                    unfinished = self._watch_thread_limit(flying)
603 6fa30b1b Stavros Sachtouris
                    for thread in set(flying).difference(unfinished):
604 6fa30b1b Stavros Sachtouris
                        if thread.exception:
605 6fa30b1b Stavros Sachtouris
                            failures.append(thread.kwargs['hash'])
606 6fa30b1b Stavros Sachtouris
                        if thread.isAlive():
607 6fa30b1b Stavros Sachtouris
                            flying.append(thread)
608 6fa30b1b Stavros Sachtouris
                        else:
609 6fa30b1b Stavros Sachtouris
                            self._cb_next()
610 6fa30b1b Stavros Sachtouris
                    flying = unfinished
611 6fa30b1b Stavros Sachtouris
                for thread in flying:
612 6fa30b1b Stavros Sachtouris
                    thread.join()
613 9d502497 Stavros Sachtouris
                    if thread.exception:
614 6fa30b1b Stavros Sachtouris
                        failures.append(thread.kwargs['hash'])
615 6fa30b1b Stavros Sachtouris
                    self._cb_next()
616 6fa30b1b Stavros Sachtouris
                missing = failures
617 6fa30b1b Stavros Sachtouris
                if missing and len(missing) == old_failures:
618 6fa30b1b Stavros Sachtouris
                    tries -= 1
619 6fa30b1b Stavros Sachtouris
                old_failures = len(missing)
620 6fa30b1b Stavros Sachtouris
            if missing:
621 6fa30b1b Stavros Sachtouris
                raise ClientError(
622 6fa30b1b Stavros Sachtouris
                    '%s blocks failed to upload' % len(missing),
623 6fa30b1b Stavros Sachtouris
                    details=['%s' % thread.exception for thread in missing])
624 f27ed9a0 Stavros Sachtouris
        except KeyboardInterrupt:
625 6069b53b Stavros Sachtouris
            sendlog.info('- - - wait for threads to finish')
626 f27ed9a0 Stavros Sachtouris
            for thread in activethreads():
627 f27ed9a0 Stavros Sachtouris
                thread.join()
628 f27ed9a0 Stavros Sachtouris
            raise
629 f27ed9a0 Stavros Sachtouris
630 3c216009 Stavros Sachtouris
        r = self.object_put(
631 f27ed9a0 Stavros Sachtouris
            obj,
632 3dabe5d2 Stavros Sachtouris
            format='json',
633 3dabe5d2 Stavros Sachtouris
            hashmap=True,
634 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
635 5c2058e7 Stavros Sachtouris
            content_encoding=content_encoding,
636 e9ac514e Stavros Sachtouris
            if_etag_match=if_etag_match,
637 524d9cdd Stavros Sachtouris
            if_etag_not_match='*' if if_not_exist else None,
638 524d9cdd Stavros Sachtouris
            etag=etag,
639 3dabe5d2 Stavros Sachtouris
            json=hashmap,
640 50165863 Stavros Sachtouris
            permissions=sharing,
641 50165863 Stavros Sachtouris
            public=public,
642 3dabe5d2 Stavros Sachtouris
            success=201)
643 3c216009 Stavros Sachtouris
        return r.headers
644 3dabe5d2 Stavros Sachtouris
645 f27ed9a0 Stavros Sachtouris
    # download_* auxiliary methods
646 fbfee225 Stavros Sachtouris
    def _get_remote_blocks_info(self, obj, **restargs):
647 56f0908a Stavros Sachtouris
        #retrieve object hashmap
648 3dabe5d2 Stavros Sachtouris
        myrange = restargs.pop('data_range', None)
649 319be41b Stavros Sachtouris
        hashmap = self.get_object_hashmap(obj, **restargs)
650 642f1bbd Stavros Sachtouris
        restargs['data_range'] = myrange
651 56f0908a Stavros Sachtouris
        blocksize = int(hashmap['block_size'])
652 56f0908a Stavros Sachtouris
        blockhash = hashmap['block_hash']
653 56f0908a Stavros Sachtouris
        total_size = hashmap['bytes']
654 fbfee225 Stavros Sachtouris
        #assert total_size/blocksize + 1 == len(hashmap['hashes'])
655 56f0908a Stavros Sachtouris
        map_dict = {}
656 fbfee225 Stavros Sachtouris
        for i, h in enumerate(hashmap['hashes']):
657 ca7f78c0 Stavros Sachtouris
            #  map_dict[h] = i   CHAGE
658 ca7f78c0 Stavros Sachtouris
            if h in map_dict:
659 ca7f78c0 Stavros Sachtouris
                map_dict[h].append(i)
660 ca7f78c0 Stavros Sachtouris
            else:
661 ca7f78c0 Stavros Sachtouris
                map_dict[h] = [i]
662 fbfee225 Stavros Sachtouris
        return (blocksize, blockhash, total_size, hashmap['hashes'], map_dict)
663 64ab4c13 Stavros Sachtouris
664 24ff0a35 Stavros Sachtouris
    def _dump_blocks_sync(
665 7806f19d Stavros Sachtouris
            self, obj, remote_hashes, blocksize, total_size, dst, crange,
666 24ff0a35 Stavros Sachtouris
            **args):
667 edc1182f Stavros Sachtouris
        if not total_size:
668 edc1182f Stavros Sachtouris
            return
669 fbfee225 Stavros Sachtouris
        for blockid, blockhash in enumerate(remote_hashes):
670 24ff0a35 Stavros Sachtouris
            if blockhash:
671 24ff0a35 Stavros Sachtouris
                start = blocksize * blockid
672 24ff0a35 Stavros Sachtouris
                is_last = start + blocksize > total_size
673 24ff0a35 Stavros Sachtouris
                end = (total_size - 1) if is_last else (start + blocksize - 1)
674 776b275c Stavros Sachtouris
                data_range = _range_up(start, end, total_size, crange)
675 776b275c Stavros Sachtouris
                if not data_range:
676 776b275c Stavros Sachtouris
                    self._cb_next()
677 776b275c Stavros Sachtouris
                    continue
678 776b275c Stavros Sachtouris
                args['data_range'] = 'bytes=%s' % data_range
679 24ff0a35 Stavros Sachtouris
                r = self.object_get(obj, success=(200, 206), **args)
680 24ff0a35 Stavros Sachtouris
                self._cb_next()
681 24ff0a35 Stavros Sachtouris
                dst.write(r.content)
682 24ff0a35 Stavros Sachtouris
                dst.flush()
683 fbfee225 Stavros Sachtouris
684 24ff0a35 Stavros Sachtouris
    def _get_block_async(self, obj, **args):
685 24ff0a35 Stavros Sachtouris
        event = SilentEvent(self.object_get, obj, success=(200, 206), **args)
686 e02728f9 Stavros Sachtouris
        event.start()
687 e02728f9 Stavros Sachtouris
        return event
688 fb0cd49a Stavros Sachtouris
689 48c3782c Stavros Sachtouris
    def _hash_from_file(self, fp, start, size, blockhash):
690 48c3782c Stavros Sachtouris
        fp.seek(start)
691 4f228300 Stavros Sachtouris
        block = readall(fp, size)
692 48c3782c Stavros Sachtouris
        h = newhashlib(blockhash)
693 48c3782c Stavros Sachtouris
        h.update(block.strip('\x00'))
694 48c3782c Stavros Sachtouris
        return hexlify(h.digest())
695 48c3782c Stavros Sachtouris
696 28cbc3c2 Stavros Sachtouris
    def _thread2file(self, flying, blockids, local_file, offset=0, **restargs):
697 22fc09fb Stavros Sachtouris
        """write the results of a greenleted rest call to a file
698 f5f2dc53 Stavros Sachtouris

699 f5f2dc53 Stavros Sachtouris
        :param offset: the offset of the file up to blocksize
700 f5f2dc53 Stavros Sachtouris
        - e.g. if the range is 10-100, all blocks will be written to
701 f5f2dc53 Stavros Sachtouris
        normal_position - 10
702 f5f2dc53 Stavros Sachtouris
        """
703 0fbc8a52 Stavros Sachtouris
        for key, g in flying.items():
704 28cbc3c2 Stavros Sachtouris
            if g.isAlive():
705 28cbc3c2 Stavros Sachtouris
                continue
706 28cbc3c2 Stavros Sachtouris
            if g.exception:
707 28cbc3c2 Stavros Sachtouris
                raise g.exception
708 28cbc3c2 Stavros Sachtouris
            block = g.value.content
709 28cbc3c2 Stavros Sachtouris
            for block_start in blockids[key]:
710 28cbc3c2 Stavros Sachtouris
                local_file.seek(block_start + offset)
711 fbfee225 Stavros Sachtouris
                local_file.write(block)
712 fbfee225 Stavros Sachtouris
                self._cb_next()
713 28cbc3c2 Stavros Sachtouris
            flying.pop(key)
714 28cbc3c2 Stavros Sachtouris
            blockids.pop(key)
715 fbfee225 Stavros Sachtouris
        local_file.flush()
716 fbfee225 Stavros Sachtouris
717 24ff0a35 Stavros Sachtouris
    def _dump_blocks_async(
718 24ff0a35 Stavros Sachtouris
            self, obj, remote_hashes, blocksize, total_size, local_file,
719 24ff0a35 Stavros Sachtouris
            blockhash=None, resume=False, filerange=None, **restargs):
720 973fbcad Stavros Sachtouris
        file_size = fstat(local_file.fileno()).st_size if resume else 0
721 28cbc3c2 Stavros Sachtouris
        flying = dict()
722 28cbc3c2 Stavros Sachtouris
        blockid_dict = dict()
723 22fc09fb Stavros Sachtouris
        offset = 0
724 f27ed9a0 Stavros Sachtouris
725 cad39033 Stavros Sachtouris
        self._init_thread_limit()
726 ca7f78c0 Stavros Sachtouris
        for block_hash, blockids in remote_hashes.items():
727 28cbc3c2 Stavros Sachtouris
            blockids = [blk * blocksize for blk in blockids]
728 28cbc3c2 Stavros Sachtouris
            unsaved = [blk for blk in blockids if not (
729 28cbc3c2 Stavros Sachtouris
                blk < file_size and block_hash == self._hash_from_file(
730 28cbc3c2 Stavros Sachtouris
                        local_file, blk, blocksize, blockhash))]
731 28cbc3c2 Stavros Sachtouris
            self._cb_next(len(blockids) - len(unsaved))
732 28cbc3c2 Stavros Sachtouris
            if unsaved:
733 28cbc3c2 Stavros Sachtouris
                key = unsaved[0]
734 438efab2 Stavros Sachtouris
                self._watch_thread_limit(flying.values())
735 438efab2 Stavros Sachtouris
                self._thread2file(
736 438efab2 Stavros Sachtouris
                    flying, blockid_dict, local_file, offset,
737 438efab2 Stavros Sachtouris
                    **restargs)
738 438efab2 Stavros Sachtouris
                end = total_size - 1 if (
739 438efab2 Stavros Sachtouris
                    key + blocksize > total_size) else key + blocksize - 1
740 438efab2 Stavros Sachtouris
                if end < key:
741 438efab2 Stavros Sachtouris
                    self._cb_next()
742 438efab2 Stavros Sachtouris
                    continue
743 438efab2 Stavros Sachtouris
                data_range = _range_up(key, end, total_size, filerange)
744 438efab2 Stavros Sachtouris
                if not data_range:
745 438efab2 Stavros Sachtouris
                    self._cb_next()
746 438efab2 Stavros Sachtouris
                    continue
747 438efab2 Stavros Sachtouris
                restargs[
748 438efab2 Stavros Sachtouris
                    'async_headers'] = {'Range': 'bytes=%s' % data_range}
749 438efab2 Stavros Sachtouris
                flying[key] = self._get_block_async(obj, **restargs)
750 438efab2 Stavros Sachtouris
                blockid_dict[key] = unsaved
751 fbfee225 Stavros Sachtouris
752 e02728f9 Stavros Sachtouris
        for thread in flying.values():
753 e02728f9 Stavros Sachtouris
            thread.join()
754 28cbc3c2 Stavros Sachtouris
        self._thread2file(flying, blockid_dict, local_file, offset, **restargs)
755 fbfee225 Stavros Sachtouris
756 24ff0a35 Stavros Sachtouris
    def download_object(
757 24ff0a35 Stavros Sachtouris
            self, obj, dst,
758 24ff0a35 Stavros Sachtouris
            download_cb=None,
759 24ff0a35 Stavros Sachtouris
            version=None,
760 24ff0a35 Stavros Sachtouris
            resume=False,
761 24ff0a35 Stavros Sachtouris
            range_str=None,
762 24ff0a35 Stavros Sachtouris
            if_match=None,
763 24ff0a35 Stavros Sachtouris
            if_none_match=None,
764 24ff0a35 Stavros Sachtouris
            if_modified_since=None,
765 24ff0a35 Stavros Sachtouris
            if_unmodified_since=None):
766 f5f2dc53 Stavros Sachtouris
        """Download an object (multiple connections, random blocks)
767 4375e020 Stavros Sachtouris

768 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
769 4375e020 Stavros Sachtouris

770 4375e020 Stavros Sachtouris
        :param dst: open file descriptor (wb+)
771 4375e020 Stavros Sachtouris

772 4375e020 Stavros Sachtouris
        :param download_cb: optional progress.bar object for downloading
773 4375e020 Stavros Sachtouris

774 4375e020 Stavros Sachtouris
        :param version: (str) file version
775 4375e020 Stavros Sachtouris

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

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

780 4375e020 Stavros Sachtouris
        :param if_match: (str)
781 4375e020 Stavros Sachtouris

782 4375e020 Stavros Sachtouris
        :param if_none_match: (str)
783 4375e020 Stavros Sachtouris

784 4375e020 Stavros Sachtouris
        :param if_modified_since: (str) formated date
785 4375e020 Stavros Sachtouris

786 f5f2dc53 Stavros Sachtouris
        :param if_unmodified_since: (str) formated date"""
787 24ff0a35 Stavros Sachtouris
        restargs = dict(
788 24ff0a35 Stavros Sachtouris
            version=version,
789 24ff0a35 Stavros Sachtouris
            data_range=None if range_str is None else 'bytes=%s' % range_str,
790 fbfee225 Stavros Sachtouris
            if_match=if_match,
791 fbfee225 Stavros Sachtouris
            if_none_match=if_none_match,
792 fbfee225 Stavros Sachtouris
            if_modified_since=if_modified_since,
793 fbfee225 Stavros Sachtouris
            if_unmodified_since=if_unmodified_since)
794 fbfee225 Stavros Sachtouris
795 24ff0a35 Stavros Sachtouris
        (
796 24ff0a35 Stavros Sachtouris
            blocksize,
797 fbfee225 Stavros Sachtouris
            blockhash,
798 fbfee225 Stavros Sachtouris
            total_size,
799 3dabe5d2 Stavros Sachtouris
            hash_list,
800 fbfee225 Stavros Sachtouris
            remote_hashes) = self._get_remote_blocks_info(obj, **restargs)
801 fbfee225 Stavros Sachtouris
        assert total_size >= 0
802 fbfee225 Stavros Sachtouris
803 fbfee225 Stavros Sachtouris
        if download_cb:
804 ca7f78c0 Stavros Sachtouris
            self.progress_bar_gen = download_cb(len(hash_list))
805 fbfee225 Stavros Sachtouris
            self._cb_next()
806 fbfee225 Stavros Sachtouris
807 fbfee225 Stavros Sachtouris
        if dst.isatty():
808 24ff0a35 Stavros Sachtouris
            self._dump_blocks_sync(
809 24ff0a35 Stavros Sachtouris
                obj,
810 3dabe5d2 Stavros Sachtouris
                hash_list,
811 3dabe5d2 Stavros Sachtouris
                blocksize,
812 3dabe5d2 Stavros Sachtouris
                total_size,
813 3dabe5d2 Stavros Sachtouris
                dst,
814 24ff0a35 Stavros Sachtouris
                range_str,
815 3dabe5d2 Stavros Sachtouris
                **restargs)
816 699d3bb1 Stavros Sachtouris
        else:
817 24ff0a35 Stavros Sachtouris
            self._dump_blocks_async(
818 24ff0a35 Stavros Sachtouris
                obj,
819 3dabe5d2 Stavros Sachtouris
                remote_hashes,
820 3dabe5d2 Stavros Sachtouris
                blocksize,
821 3dabe5d2 Stavros Sachtouris
                total_size,
822 3dabe5d2 Stavros Sachtouris
                dst,
823 3dabe5d2 Stavros Sachtouris
                blockhash,
824 3dabe5d2 Stavros Sachtouris
                resume,
825 24ff0a35 Stavros Sachtouris
                range_str,
826 3dabe5d2 Stavros Sachtouris
                **restargs)
827 24ff0a35 Stavros Sachtouris
            if not range_str:
828 22fc09fb Stavros Sachtouris
                dst.truncate(total_size)
829 5b263ba2 Stavros Sachtouris
830 fbfee225 Stavros Sachtouris
        self._complete_cb()
831 fbfee225 Stavros Sachtouris
832 49cc29b2 Stavros Sachtouris
    def download_to_string(
833 49cc29b2 Stavros Sachtouris
            self, obj,
834 49cc29b2 Stavros Sachtouris
            download_cb=None,
835 49cc29b2 Stavros Sachtouris
            version=None,
836 49cc29b2 Stavros Sachtouris
            range_str=None,
837 49cc29b2 Stavros Sachtouris
            if_match=None,
838 49cc29b2 Stavros Sachtouris
            if_none_match=None,
839 49cc29b2 Stavros Sachtouris
            if_modified_since=None,
840 49cc29b2 Stavros Sachtouris
            if_unmodified_since=None):
841 0fbc8a52 Stavros Sachtouris
        """Download an object to a string (multiple connections). This method
842 0fbc8a52 Stavros Sachtouris
        uses threads for http requests, but stores all content in memory.
843 49cc29b2 Stavros Sachtouris

844 49cc29b2 Stavros Sachtouris
        :param obj: (str) remote object path
845 49cc29b2 Stavros Sachtouris

846 49cc29b2 Stavros Sachtouris
        :param download_cb: optional progress.bar object for downloading
847 49cc29b2 Stavros Sachtouris

848 49cc29b2 Stavros Sachtouris
        :param version: (str) file version
849 49cc29b2 Stavros Sachtouris

850 49cc29b2 Stavros Sachtouris
        :param range_str: (str) from, to are file positions (int) in bytes
851 49cc29b2 Stavros Sachtouris

852 49cc29b2 Stavros Sachtouris
        :param if_match: (str)
853 49cc29b2 Stavros Sachtouris

854 49cc29b2 Stavros Sachtouris
        :param if_none_match: (str)
855 49cc29b2 Stavros Sachtouris

856 49cc29b2 Stavros Sachtouris
        :param if_modified_since: (str) formated date
857 49cc29b2 Stavros Sachtouris

858 49cc29b2 Stavros Sachtouris
        :param if_unmodified_since: (str) formated date
859 49cc29b2 Stavros Sachtouris

860 49cc29b2 Stavros Sachtouris
        :returns: (str) the whole object contents
861 49cc29b2 Stavros Sachtouris
        """
862 49cc29b2 Stavros Sachtouris
        restargs = dict(
863 49cc29b2 Stavros Sachtouris
            version=version,
864 49cc29b2 Stavros Sachtouris
            data_range=None if range_str is None else 'bytes=%s' % range_str,
865 49cc29b2 Stavros Sachtouris
            if_match=if_match,
866 49cc29b2 Stavros Sachtouris
            if_none_match=if_none_match,
867 49cc29b2 Stavros Sachtouris
            if_modified_since=if_modified_since,
868 49cc29b2 Stavros Sachtouris
            if_unmodified_since=if_unmodified_since)
869 49cc29b2 Stavros Sachtouris
870 49cc29b2 Stavros Sachtouris
        (
871 49cc29b2 Stavros Sachtouris
            blocksize,
872 49cc29b2 Stavros Sachtouris
            blockhash,
873 49cc29b2 Stavros Sachtouris
            total_size,
874 49cc29b2 Stavros Sachtouris
            hash_list,
875 49cc29b2 Stavros Sachtouris
            remote_hashes) = self._get_remote_blocks_info(obj, **restargs)
876 49cc29b2 Stavros Sachtouris
        assert total_size >= 0
877 49cc29b2 Stavros Sachtouris
878 49cc29b2 Stavros Sachtouris
        if download_cb:
879 49cc29b2 Stavros Sachtouris
            self.progress_bar_gen = download_cb(len(hash_list))
880 49cc29b2 Stavros Sachtouris
            self._cb_next()
881 49cc29b2 Stavros Sachtouris
882 0fbc8a52 Stavros Sachtouris
        num_of_blocks = len(remote_hashes)
883 0fbc8a52 Stavros Sachtouris
        ret = [''] * num_of_blocks
884 0fbc8a52 Stavros Sachtouris
        self._init_thread_limit()
885 0fbc8a52 Stavros Sachtouris
        flying = dict()
886 5655d560 Stavros Sachtouris
        try:
887 5655d560 Stavros Sachtouris
            for blockid, blockhash in enumerate(remote_hashes):
888 5655d560 Stavros Sachtouris
                start = blocksize * blockid
889 5655d560 Stavros Sachtouris
                is_last = start + blocksize > total_size
890 5655d560 Stavros Sachtouris
                end = (total_size - 1) if is_last else (start + blocksize - 1)
891 776b275c Stavros Sachtouris
                data_range_str = _range_up(start, end, end, range_str)
892 776b275c Stavros Sachtouris
                if data_range_str:
893 5655d560 Stavros Sachtouris
                    self._watch_thread_limit(flying.values())
894 776b275c Stavros Sachtouris
                    restargs['data_range'] = 'bytes=%s' % data_range_str
895 5655d560 Stavros Sachtouris
                    flying[blockid] = self._get_block_async(obj, **restargs)
896 5655d560 Stavros Sachtouris
                for runid, thread in flying.items():
897 5655d560 Stavros Sachtouris
                    if (blockid + 1) == num_of_blocks:
898 5655d560 Stavros Sachtouris
                        thread.join()
899 5655d560 Stavros Sachtouris
                    elif thread.isAlive():
900 5655d560 Stavros Sachtouris
                        continue
901 5655d560 Stavros Sachtouris
                    if thread.exception:
902 5655d560 Stavros Sachtouris
                        raise thread.exception
903 5655d560 Stavros Sachtouris
                    ret[runid] = thread.value.content
904 5655d560 Stavros Sachtouris
                    self._cb_next()
905 5655d560 Stavros Sachtouris
                    flying.pop(runid)
906 5655d560 Stavros Sachtouris
            return ''.join(ret)
907 5655d560 Stavros Sachtouris
        except KeyboardInterrupt:
908 5655d560 Stavros Sachtouris
            sendlog.info('- - - wait for threads to finish')
909 5655d560 Stavros Sachtouris
            for thread in activethreads():
910 5655d560 Stavros Sachtouris
                thread.join()
911 49cc29b2 Stavros Sachtouris
912 fbfee225 Stavros Sachtouris
    #Command Progress Bar method
913 28cbc3c2 Stavros Sachtouris
    def _cb_next(self, step=1):
914 fbfee225 Stavros Sachtouris
        if hasattr(self, 'progress_bar_gen'):
915 fbfee225 Stavros Sachtouris
            try:
916 e5c76b1a Stavros Sachtouris
                for i in xrange(step):
917 e5c76b1a Stavros Sachtouris
                    self.progress_bar_gen.next()
918 fbfee225 Stavros Sachtouris
            except:
919 fbfee225 Stavros Sachtouris
                pass
920 3dabe5d2 Stavros Sachtouris
921 fbfee225 Stavros Sachtouris
    def _complete_cb(self):
922 fbfee225 Stavros Sachtouris
        while True:
923 fbfee225 Stavros Sachtouris
            try:
924 e5c76b1a Stavros Sachtouris
                self.progress_bar_gen.next()
925 fbfee225 Stavros Sachtouris
            except:
926 fbfee225 Stavros Sachtouris
                break
927 b1713259 Stavros Sachtouris
928 24ff0a35 Stavros Sachtouris
    def get_object_hashmap(
929 24ff0a35 Stavros Sachtouris
            self, obj,
930 24ff0a35 Stavros Sachtouris
            version=None,
931 24ff0a35 Stavros Sachtouris
            if_match=None,
932 24ff0a35 Stavros Sachtouris
            if_none_match=None,
933 24ff0a35 Stavros Sachtouris
            if_modified_since=None,
934 776b275c Stavros Sachtouris
            if_unmodified_since=None):
935 4375e020 Stavros Sachtouris
        """
936 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
937 4375e020 Stavros Sachtouris

938 4375e020 Stavros Sachtouris
        :param if_match: (str)
939 4375e020 Stavros Sachtouris

940 4375e020 Stavros Sachtouris
        :param if_none_match: (str)
941 4375e020 Stavros Sachtouris

942 4375e020 Stavros Sachtouris
        :param if_modified_since: (str) formated date
943 4375e020 Stavros Sachtouris

944 4375e020 Stavros Sachtouris
        :param if_unmodified_since: (str) formated date
945 4375e020 Stavros Sachtouris

946 4375e020 Stavros Sachtouris
        :returns: (list)
947 4375e020 Stavros Sachtouris
        """
948 d804de82 Stavros Sachtouris
        try:
949 24ff0a35 Stavros Sachtouris
            r = self.object_get(
950 24ff0a35 Stavros Sachtouris
                obj,
951 3dabe5d2 Stavros Sachtouris
                hashmap=True,
952 3dabe5d2 Stavros Sachtouris
                version=version,
953 3dabe5d2 Stavros Sachtouris
                if_etag_match=if_match,
954 3dabe5d2 Stavros Sachtouris
                if_etag_not_match=if_none_match,
955 3dabe5d2 Stavros Sachtouris
                if_modified_since=if_modified_since,
956 776b275c Stavros Sachtouris
                if_unmodified_since=if_unmodified_since)
957 d804de82 Stavros Sachtouris
        except ClientError as err:
958 d804de82 Stavros Sachtouris
            if err.status == 304 or err.status == 412:
959 d804de82 Stavros Sachtouris
                return {}
960 d804de82 Stavros Sachtouris
            raise
961 64ab4c13 Stavros Sachtouris
        return r.json
962 56f0908a Stavros Sachtouris
963 3a9e54b0 Stavros Sachtouris
    def set_account_group(self, group, usernames):
964 4375e020 Stavros Sachtouris
        """
965 4375e020 Stavros Sachtouris
        :param group: (str)
966 4375e020 Stavros Sachtouris

967 4375e020 Stavros Sachtouris
        :param usernames: (list)
968 4375e020 Stavros Sachtouris
        """
969 915b99b5 Stavros Sachtouris
        r = self.account_post(update=True, groups={group: usernames})
970 915b99b5 Stavros Sachtouris
        return r
971 eb903ba7 Stavros Sachtouris
972 c2867610 Stavros Sachtouris
    def del_account_group(self, group):
973 4375e020 Stavros Sachtouris
        """
974 4375e020 Stavros Sachtouris
        :param group: (str)
975 4375e020 Stavros Sachtouris
        """
976 c2b5da2f Stavros Sachtouris
        self.account_post(update=True, groups={group: []})
977 c2867610 Stavros Sachtouris
978 8af4cc0b Stavros Sachtouris
    def get_account_info(self, until=None):
979 4375e020 Stavros Sachtouris
        """
980 4375e020 Stavros Sachtouris
        :param until: (str) formated date
981 4375e020 Stavros Sachtouris

982 4375e020 Stavros Sachtouris
        :returns: (dict)
983 4375e020 Stavros Sachtouris
        """
984 8af4cc0b Stavros Sachtouris
        r = self.account_head(until=until)
985 6657ec8c Stavros Sachtouris
        if r.status_code == 401:
986 24851aa5 Stavros Sachtouris
            raise ClientError("No authorization", status=401)
987 64ab4c13 Stavros Sachtouris
        return r.headers
988 6657ec8c Stavros Sachtouris
989 d1856abf Stavros Sachtouris
    def get_account_quota(self):
990 4375e020 Stavros Sachtouris
        """
991 4375e020 Stavros Sachtouris
        :returns: (dict)
992 4375e020 Stavros Sachtouris
        """
993 24ff0a35 Stavros Sachtouris
        return filter_in(
994 24ff0a35 Stavros Sachtouris
            self.get_account_info(),
995 3dabe5d2 Stavros Sachtouris
            'X-Account-Policy-Quota',
996 3dabe5d2 Stavros Sachtouris
            exactMatch=True)
997 d1856abf Stavros Sachtouris
998 df0045d8 Stavros Sachtouris
    #def get_account_versioning(self):
999 df0045d8 Stavros Sachtouris
    #    """
1000 df0045d8 Stavros Sachtouris
    #    :returns: (dict)
1001 df0045d8 Stavros Sachtouris
    #    """
1002 df0045d8 Stavros Sachtouris
    #    return filter_in(
1003 df0045d8 Stavros Sachtouris
    #        self.get_account_info(),
1004 df0045d8 Stavros Sachtouris
    #        'X-Account-Policy-Versioning',
1005 df0045d8 Stavros Sachtouris
    #        exactMatch=True)
1006 e6b39366 Stavros Sachtouris
1007 8af4cc0b Stavros Sachtouris
    def get_account_meta(self, until=None):
1008 4375e020 Stavros Sachtouris
        """
1009 8f91e50c Stavros Sachtouris
        :param until: (str) formated date
1010 4375e020 Stavros Sachtouris

1011 4375e020 Stavros Sachtouris
        :returns: (dict)
1012 4375e020 Stavros Sachtouris
        """
1013 3dabe5d2 Stavros Sachtouris
        return filter_in(self.get_account_info(until=until), 'X-Account-Meta-')
1014 af3b2b36 Stavros Sachtouris
1015 c2867610 Stavros Sachtouris
    def get_account_group(self):
1016 4375e020 Stavros Sachtouris
        """
1017 4375e020 Stavros Sachtouris
        :returns: (dict)
1018 4375e020 Stavros Sachtouris
        """
1019 c2867610 Stavros Sachtouris
        return filter_in(self.get_account_info(), 'X-Account-Group-')
1020 c2867610 Stavros Sachtouris
1021 af3b2b36 Stavros Sachtouris
    def set_account_meta(self, metapairs):
1022 4375e020 Stavros Sachtouris
        """
1023 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
1024 4375e020 Stavros Sachtouris
        """
1025 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
1026 915b99b5 Stavros Sachtouris
        r = self.account_post(update=True, metadata=metapairs)
1027 915b99b5 Stavros Sachtouris
        return r.headers
1028 af3b2b36 Stavros Sachtouris
1029 379cd4bb Stavros Sachtouris
    def del_account_meta(self, metakey):
1030 4375e020 Stavros Sachtouris
        """
1031 4375e020 Stavros Sachtouris
        :param metakey: (str) metadatum key
1032 4375e020 Stavros Sachtouris
        """
1033 915b99b5 Stavros Sachtouris
        r = self.account_post(update=True, metadata={metakey: ''})
1034 915b99b5 Stavros Sachtouris
        return r.headers
1035 379cd4bb Stavros Sachtouris
1036 df0045d8 Stavros Sachtouris
    #def set_account_quota(self, quota):
1037 df0045d8 Stavros Sachtouris
    #    """
1038 df0045d8 Stavros Sachtouris
    #    :param quota: (int)
1039 df0045d8 Stavros Sachtouris
    #    """
1040 df0045d8 Stavros Sachtouris
    #    self.account_post(update=True, quota=quota)
1041 df0045d8 Stavros Sachtouris
1042 df0045d8 Stavros Sachtouris
    #def set_account_versioning(self, versioning):
1043 df0045d8 Stavros Sachtouris
    #    """
1044 df0045d8 Stavros Sachtouris
    #    :param versioning: (str)
1045 df0045d8 Stavros Sachtouris
    #    """
1046 df0045d8 Stavros Sachtouris
    #    r = self.account_post(update=True, versioning=versioning)
1047 df0045d8 Stavros Sachtouris
    #    return r.headers
1048 d1856abf Stavros Sachtouris
1049 4fd88feb Stavros Sachtouris
    def list_containers(self):
1050 4375e020 Stavros Sachtouris
        """
1051 4375e020 Stavros Sachtouris
        :returns: (dict)
1052 4375e020 Stavros Sachtouris
        """
1053 4fd88feb Stavros Sachtouris
        r = self.account_get()
1054 64ab4c13 Stavros Sachtouris
        return r.json
1055 b758e547 Stavros Sachtouris
1056 a298f2ab Stavros Sachtouris
    def del_container(self, until=None, delimiter=None):
1057 4375e020 Stavros Sachtouris
        """
1058 4375e020 Stavros Sachtouris
        :param until: (str) formated date
1059 4375e020 Stavros Sachtouris

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

1062 4375e020 Stavros Sachtouris
        :raises ClientError: 404 Container does not exist
1063 4375e020 Stavros Sachtouris

1064 4375e020 Stavros Sachtouris
        :raises ClientError: 409 Container is not empty
1065 4375e020 Stavros Sachtouris
        """
1066 277ca4ed Dionysis Zindros
        self._assert_container()
1067 2005b18e Stavros Sachtouris
        r = self.container_delete(
1068 2005b18e Stavros Sachtouris
            until=until,
1069 3dabe5d2 Stavros Sachtouris
            delimiter=delimiter,
1070 3dabe5d2 Stavros Sachtouris
            success=(204, 404, 409))
1071 a298f2ab Stavros Sachtouris
        if r.status_code == 404:
1072 24ff0a35 Stavros Sachtouris
            raise ClientError(
1073 24ff0a35 Stavros Sachtouris
                'Container "%s" does not exist' % self.container,
1074 3dabe5d2 Stavros Sachtouris
                r.status_code)
1075 a298f2ab Stavros Sachtouris
        elif r.status_code == 409:
1076 24ff0a35 Stavros Sachtouris
            raise ClientError(
1077 24ff0a35 Stavros Sachtouris
                'Container "%s" is not empty' % self.container,
1078 3dabe5d2 Stavros Sachtouris
                r.status_code)
1079 5655d560 Stavros Sachtouris
        return r.headers
1080 a298f2ab Stavros Sachtouris
1081 bae347d3 Stavros Sachtouris
    def get_container_versioning(self, container=None):
1082 4375e020 Stavros Sachtouris
        """
1083 4375e020 Stavros Sachtouris
        :param container: (str)
1084 4375e020 Stavros Sachtouris

1085 4375e020 Stavros Sachtouris
        :returns: (dict)
1086 4375e020 Stavros Sachtouris
        """
1087 bae347d3 Stavros Sachtouris
        cnt_back_up = self.container
1088 bae347d3 Stavros Sachtouris
        try:
1089 bae347d3 Stavros Sachtouris
            self.container = container or cnt_back_up
1090 bae347d3 Stavros Sachtouris
            return filter_in(
1091 bae347d3 Stavros Sachtouris
                self.get_container_info(),
1092 bae347d3 Stavros Sachtouris
                'X-Container-Policy-Versioning')
1093 bae347d3 Stavros Sachtouris
        finally:
1094 bae347d3 Stavros Sachtouris
            self.container = cnt_back_up
1095 d1856abf Stavros Sachtouris
1096 3ed6dbde Stavros Sachtouris
    def get_container_limit(self, container=None):
1097 4375e020 Stavros Sachtouris
        """
1098 4375e020 Stavros Sachtouris
        :param container: (str)
1099 4375e020 Stavros Sachtouris

1100 4375e020 Stavros Sachtouris
        :returns: (dict)
1101 4375e020 Stavros Sachtouris
        """
1102 1879e310 Stavros Sachtouris
        cnt_back_up = self.container
1103 1879e310 Stavros Sachtouris
        try:
1104 1879e310 Stavros Sachtouris
            self.container = container or cnt_back_up
1105 1879e310 Stavros Sachtouris
            return filter_in(
1106 1879e310 Stavros Sachtouris
                self.get_container_info(),
1107 1879e310 Stavros Sachtouris
                'X-Container-Policy-Quota')
1108 1879e310 Stavros Sachtouris
        finally:
1109 1879e310 Stavros Sachtouris
            self.container = cnt_back_up
1110 e6b39366 Stavros Sachtouris
1111 3dabe5d2 Stavros Sachtouris
    def get_container_info(self, until=None):
1112 4375e020 Stavros Sachtouris
        """
1113 4375e020 Stavros Sachtouris
        :param until: (str) formated date
1114 4375e020 Stavros Sachtouris

1115 4375e020 Stavros Sachtouris
        :returns: (dict)
1116 f91bc6b1 Stavros Sachtouris

1117 f91bc6b1 Stavros Sachtouris
        :raises ClientError: 404 Container not found
1118 4375e020 Stavros Sachtouris
        """
1119 f91bc6b1 Stavros Sachtouris
        try:
1120 f91bc6b1 Stavros Sachtouris
            r = self.container_head(until=until)
1121 f91bc6b1 Stavros Sachtouris
        except ClientError as err:
1122 f91bc6b1 Stavros Sachtouris
            err.details.append('for container %s' % self.container)
1123 f91bc6b1 Stavros Sachtouris
            raise err
1124 8af4cc0b Stavros Sachtouris
        return r.headers
1125 8af4cc0b Stavros Sachtouris
1126 3dabe5d2 Stavros Sachtouris
    def get_container_meta(self, until=None):
1127 4375e020 Stavros Sachtouris
        """
1128 4375e020 Stavros Sachtouris
        :param until: (str) formated date
1129 4375e020 Stavros Sachtouris

1130 4375e020 Stavros Sachtouris
        :returns: (dict)
1131 4375e020 Stavros Sachtouris
        """
1132 24ff0a35 Stavros Sachtouris
        return filter_in(
1133 24ff0a35 Stavros Sachtouris
            self.get_container_info(until=until),
1134 3dabe5d2 Stavros Sachtouris
            'X-Container-Meta')
1135 e6b39366 Stavros Sachtouris
1136 3dabe5d2 Stavros Sachtouris
    def get_container_object_meta(self, until=None):
1137 4375e020 Stavros Sachtouris
        """
1138 4375e020 Stavros Sachtouris
        :param until: (str) formated date
1139 4375e020 Stavros Sachtouris

1140 4375e020 Stavros Sachtouris
        :returns: (dict)
1141 4375e020 Stavros Sachtouris
        """
1142 24ff0a35 Stavros Sachtouris
        return filter_in(
1143 24ff0a35 Stavros Sachtouris
            self.get_container_info(until=until),
1144 3dabe5d2 Stavros Sachtouris
            'X-Container-Object-Meta')
1145 e6b39366 Stavros Sachtouris
1146 af3b2b36 Stavros Sachtouris
    def set_container_meta(self, metapairs):
1147 4375e020 Stavros Sachtouris
        """
1148 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
1149 4375e020 Stavros Sachtouris
        """
1150 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
1151 915b99b5 Stavros Sachtouris
        r = self.container_post(update=True, metadata=metapairs)
1152 915b99b5 Stavros Sachtouris
        return r.headers
1153 3dabe5d2 Stavros Sachtouris
1154 3e544e5b Stavros Sachtouris
    def del_container_meta(self, metakey):
1155 4375e020 Stavros Sachtouris
        """
1156 4375e020 Stavros Sachtouris
        :param metakey: (str) metadatum key
1157 545c6c29 Stavros Sachtouris

1158 545c6c29 Stavros Sachtouris
        :returns: (dict) response headers
1159 4375e020 Stavros Sachtouris
        """
1160 915b99b5 Stavros Sachtouris
        r = self.container_post(update=True, metadata={metakey: ''})
1161 915b99b5 Stavros Sachtouris
        return r.headers
1162 e6b39366 Stavros Sachtouris
1163 326a79b9 Stavros Sachtouris
    def set_container_limit(self, limit):
1164 4375e020 Stavros Sachtouris
        """
1165 326a79b9 Stavros Sachtouris
        :param limit: (int)
1166 4375e020 Stavros Sachtouris
        """
1167 915b99b5 Stavros Sachtouris
        r = self.container_post(update=True, quota=limit)
1168 915b99b5 Stavros Sachtouris
        return r.headers
1169 d1856abf Stavros Sachtouris
1170 d1856abf Stavros Sachtouris
    def set_container_versioning(self, versioning):
1171 4375e020 Stavros Sachtouris
        """
1172 4375e020 Stavros Sachtouris
        :param versioning: (str)
1173 4375e020 Stavros Sachtouris
        """
1174 915b99b5 Stavros Sachtouris
        r = self.container_post(update=True, versioning=versioning)
1175 915b99b5 Stavros Sachtouris
        return r.headers
1176 d1856abf Stavros Sachtouris
1177 a298f2ab Stavros Sachtouris
    def del_object(self, obj, until=None, delimiter=None):
1178 4375e020 Stavros Sachtouris
        """
1179 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
1180 4375e020 Stavros Sachtouris

1181 4375e020 Stavros Sachtouris
        :param until: (str) formated date
1182 4375e020 Stavros Sachtouris

1183 4375e020 Stavros Sachtouris
        :param delimiter: (str)
1184 4375e020 Stavros Sachtouris
        """
1185 277ca4ed Dionysis Zindros
        self._assert_container()
1186 5655d560 Stavros Sachtouris
        r = self.object_delete(obj, until=until, delimiter=delimiter)
1187 5655d560 Stavros Sachtouris
        return r.headers
1188 a298f2ab Stavros Sachtouris
1189 4375e020 Stavros Sachtouris
    def set_object_meta(self, obj, metapairs):
1190 4375e020 Stavros Sachtouris
        """
1191 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
1192 4375e020 Stavros Sachtouris

1193 4375e020 Stavros Sachtouris
        :param metapairs: (dict) {key1:val1, key2:val2, ...}
1194 4375e020 Stavros Sachtouris
        """
1195 af3b2b36 Stavros Sachtouris
        assert(type(metapairs) is dict)
1196 915b99b5 Stavros Sachtouris
        r = self.object_post(obj, update=True, metadata=metapairs)
1197 915b99b5 Stavros Sachtouris
        return r.headers
1198 87688514 Stavros Sachtouris
1199 bc223d91 Stavros Sachtouris
    def del_object_meta(self, obj, metakey):
1200 4375e020 Stavros Sachtouris
        """
1201 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
1202 bc223d91 Stavros Sachtouris

1203 bc223d91 Stavros Sachtouris
        :param metakey: (str) metadatum key
1204 4375e020 Stavros Sachtouris
        """
1205 915b99b5 Stavros Sachtouris
        r = self.object_post(obj, update=True, metadata={metakey: ''})
1206 915b99b5 Stavros Sachtouris
        return r.headers
1207 6de1f262 Stavros Sachtouris
1208 bc223d91 Stavros Sachtouris
    def publish_object(self, obj):
1209 bc223d91 Stavros Sachtouris
        """
1210 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1211 5260a313 Stavros Sachtouris

1212 5260a313 Stavros Sachtouris
        :returns: (str) access url
1213 bc223d91 Stavros Sachtouris
        """
1214 c2b5da2f Stavros Sachtouris
        self.object_post(obj, update=True, public=True)
1215 5260a313 Stavros Sachtouris
        info = self.get_object_info(obj)
1216 fa382f9e Stavros Sachtouris
        return info['x-object-public']
1217 93542587 Stavros Sachtouris
        pref, sep, rest = self.base_url.partition('//')
1218 93542587 Stavros Sachtouris
        base = rest.split('/')[0]
1219 f847a0cc Stavros Sachtouris
        return '%s%s%s/%s' % (pref, sep, base, info['x-object-public'])
1220 87688514 Stavros Sachtouris
1221 bc223d91 Stavros Sachtouris
    def unpublish_object(self, obj):
1222 bc223d91 Stavros Sachtouris
        """
1223 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1224 bc223d91 Stavros Sachtouris
        """
1225 5655d560 Stavros Sachtouris
        r = self.object_post(obj, update=True, public=False)
1226 5655d560 Stavros Sachtouris
        return r.headers
1227 28470086 Stavros Sachtouris
1228 8af4cc0b Stavros Sachtouris
    def get_object_info(self, obj, version=None):
1229 bc223d91 Stavros Sachtouris
        """
1230 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1231 bc223d91 Stavros Sachtouris

1232 bc223d91 Stavros Sachtouris
        :param version: (str)
1233 bc223d91 Stavros Sachtouris

1234 bc223d91 Stavros Sachtouris
        :returns: (dict)
1235 bc223d91 Stavros Sachtouris
        """
1236 ca092af4 Stavros Sachtouris
        try:
1237 ca092af4 Stavros Sachtouris
            r = self.object_head(obj, version=version)
1238 ca092af4 Stavros Sachtouris
            return r.headers
1239 ca092af4 Stavros Sachtouris
        except ClientError as ce:
1240 ca092af4 Stavros Sachtouris
            if ce.status == 404:
1241 723e9d47 Stavros Sachtouris
                raise ClientError('Object %s not found' % obj, status=404)
1242 ca092af4 Stavros Sachtouris
            raise
1243 8af4cc0b Stavros Sachtouris
1244 8af4cc0b Stavros Sachtouris
    def get_object_meta(self, obj, version=None):
1245 bc223d91 Stavros Sachtouris
        """
1246 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1247 bc223d91 Stavros Sachtouris

1248 bc223d91 Stavros Sachtouris
        :param version: (str)
1249 bc223d91 Stavros Sachtouris

1250 bc223d91 Stavros Sachtouris
        :returns: (dict)
1251 bc223d91 Stavros Sachtouris
        """
1252 24ff0a35 Stavros Sachtouris
        return filter_in(
1253 24ff0a35 Stavros Sachtouris
            self.get_object_info(obj, version=version),
1254 3dabe5d2 Stavros Sachtouris
            'X-Object-Meta')
1255 8af4cc0b Stavros Sachtouris
1256 bc223d91 Stavros Sachtouris
    def get_object_sharing(self, obj):
1257 bc223d91 Stavros Sachtouris
        """
1258 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1259 bc223d91 Stavros Sachtouris

1260 bc223d91 Stavros Sachtouris
        :returns: (dict)
1261 bc223d91 Stavros Sachtouris
        """
1262 24ff0a35 Stavros Sachtouris
        r = filter_in(
1263 24ff0a35 Stavros Sachtouris
            self.get_object_info(obj),
1264 3dabe5d2 Stavros Sachtouris
            'X-Object-Sharing',
1265 3dabe5d2 Stavros Sachtouris
            exactMatch=True)
1266 f70616fc Stavros Sachtouris
        reply = {}
1267 f70616fc Stavros Sachtouris
        if len(r) > 0:
1268 f70616fc Stavros Sachtouris
            perms = r['x-object-sharing'].split(';')
1269 f70616fc Stavros Sachtouris
            for perm in perms:
1270 f70616fc Stavros Sachtouris
                try:
1271 f70616fc Stavros Sachtouris
                    perm.index('=')
1272 f70616fc Stavros Sachtouris
                except ValueError:
1273 f70616fc Stavros Sachtouris
                    raise ClientError('Incorrect reply format')
1274 f70616fc Stavros Sachtouris
                (key, val) = perm.strip().split('=')
1275 f70616fc Stavros Sachtouris
                reply[key] = val
1276 f70616fc Stavros Sachtouris
        return reply
1277 f49084df Stavros Sachtouris
1278 24ff0a35 Stavros Sachtouris
    def set_object_sharing(
1279 2005b18e Stavros Sachtouris
            self, obj,
1280 00336c85 Stavros Sachtouris
            read_permission=False, write_permission=False):
1281 28470086 Stavros Sachtouris
        """Give read/write permisions to an object.
1282 bc223d91 Stavros Sachtouris

1283 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1284 bc223d91 Stavros Sachtouris

1285 00336c85 Stavros Sachtouris
        :param read_permission: (list - bool) users and user groups that get
1286 00336c85 Stavros Sachtouris
            read permission for this object - False means all previous read
1287 bc223d91 Stavros Sachtouris
            permissions will be removed
1288 bc223d91 Stavros Sachtouris

1289 00336c85 Stavros Sachtouris
        :param write_permission: (list - bool) of users and user groups to get
1290 00336c85 Stavros Sachtouris
           write permission for this object - False means all previous write
1291 4067cdaf Stavros Sachtouris
           permissions will be removed
1292 915b99b5 Stavros Sachtouris

1293 915b99b5 Stavros Sachtouris
        :returns: (dict) response headers
1294 28470086 Stavros Sachtouris
        """
1295 4067cdaf Stavros Sachtouris
1296 00336c85 Stavros Sachtouris
        perms = dict(read=read_permission or '', write=write_permission or '')
1297 915b99b5 Stavros Sachtouris
        r = self.object_post(obj, update=True, permissions=perms)
1298 915b99b5 Stavros Sachtouris
        return r.headers
1299 28470086 Stavros Sachtouris
1300 bc223d91 Stavros Sachtouris
    def del_object_sharing(self, obj):
1301 bc223d91 Stavros Sachtouris
        """
1302 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1303 bc223d91 Stavros Sachtouris
        """
1304 915b99b5 Stavros Sachtouris
        return self.set_object_sharing(obj)
1305 bc223d91 Stavros Sachtouris
1306 bc223d91 Stavros Sachtouris
    def append_object(self, obj, source_file, upload_cb=None):
1307 bc223d91 Stavros Sachtouris
        """
1308 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1309 bc223d91 Stavros Sachtouris

1310 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
1311 f49084df Stavros Sachtouris

1312 bc223d91 Stavros Sachtouris
        :param upload_db: progress.bar for uploading
1313 bcabbc35 Stavros Sachtouris
        """
1314 277ca4ed Dionysis Zindros
        self._assert_container()
1315 2f749e6e Stavros Sachtouris
        meta = self.get_container_info()
1316 ab474306 Stavros Sachtouris
        blocksize = int(meta['x-container-block-size'])
1317 64ab4c13 Stavros Sachtouris
        filesize = fstat(source_file.fileno()).st_size
1318 3dabe5d2 Stavros Sachtouris
        nblocks = 1 + (filesize - 1) // blocksize
1319 ab474306 Stavros Sachtouris
        offset = 0
1320 5655d560 Stavros Sachtouris
        headers = {}
1321 ca092af4 Stavros Sachtouris
        if upload_cb:
1322 5655d560 Stavros Sachtouris
            self.progress_bar_gen = upload_cb(nblocks)
1323 5655d560 Stavros Sachtouris
            self._cb_next()
1324 5655d560 Stavros Sachtouris
        flying = {}
1325 5655d560 Stavros Sachtouris
        self._init_thread_limit()
1326 5655d560 Stavros Sachtouris
        try:
1327 5655d560 Stavros Sachtouris
            for i in range(nblocks):
1328 5655d560 Stavros Sachtouris
                block = source_file.read(min(blocksize, filesize - offset))
1329 5655d560 Stavros Sachtouris
                offset += len(block)
1330 5655d560 Stavros Sachtouris
1331 5655d560 Stavros Sachtouris
                self._watch_thread_limit(flying.values())
1332 5655d560 Stavros Sachtouris
                unfinished = {}
1333 5655d560 Stavros Sachtouris
                flying[i] = SilentEvent(
1334 5655d560 Stavros Sachtouris
                    method=self.object_post,
1335 5655d560 Stavros Sachtouris
                    obj=obj,
1336 5655d560 Stavros Sachtouris
                    update=True,
1337 5655d560 Stavros Sachtouris
                    content_range='bytes */*',
1338 5655d560 Stavros Sachtouris
                    content_type='application/octet-stream',
1339 5655d560 Stavros Sachtouris
                    content_length=len(block),
1340 5655d560 Stavros Sachtouris
                    data=block)
1341 5655d560 Stavros Sachtouris
                flying[i].start()
1342 5655d560 Stavros Sachtouris
1343 5655d560 Stavros Sachtouris
                for key, thread in flying.items():
1344 5655d560 Stavros Sachtouris
                    if thread.isAlive():
1345 5655d560 Stavros Sachtouris
                        if i < nblocks:
1346 5655d560 Stavros Sachtouris
                            unfinished[key] = thread
1347 5655d560 Stavros Sachtouris
                            continue
1348 5655d560 Stavros Sachtouris
                        thread.join()
1349 5655d560 Stavros Sachtouris
                    if thread.exception:
1350 5655d560 Stavros Sachtouris
                        raise thread.exception
1351 5655d560 Stavros Sachtouris
                    headers[key] = thread.value.headers
1352 5655d560 Stavros Sachtouris
                    self._cb_next()
1353 5655d560 Stavros Sachtouris
                flying = unfinished
1354 5655d560 Stavros Sachtouris
        except KeyboardInterrupt:
1355 5655d560 Stavros Sachtouris
            sendlog.info('- - - wait for threads to finish')
1356 5655d560 Stavros Sachtouris
            for thread in activethreads():
1357 5655d560 Stavros Sachtouris
                thread.join()
1358 3ec5c230 Stavros Sachtouris
        finally:
1359 3ec5c230 Stavros Sachtouris
            from time import sleep
1360 4e424eaa Stavros Sachtouris
            sleep(2 * len(activethreads()))
1361 5655d560 Stavros Sachtouris
        return headers.values()
1362 561116a6 Stavros Sachtouris
1363 bc223d91 Stavros Sachtouris
    def truncate_object(self, obj, upto_bytes):
1364 bc223d91 Stavros Sachtouris
        """
1365 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1366 bc223d91 Stavros Sachtouris

1367 bc223d91 Stavros Sachtouris
        :param upto_bytes: max number of bytes to leave on file
1368 915b99b5 Stavros Sachtouris

1369 915b99b5 Stavros Sachtouris
        :returns: (dict) response headers
1370 bc223d91 Stavros Sachtouris
        """
1371 915b99b5 Stavros Sachtouris
        r = self.object_post(
1372 24ff0a35 Stavros Sachtouris
            obj,
1373 3dabe5d2 Stavros Sachtouris
            update=True,
1374 3dabe5d2 Stavros Sachtouris
            content_range='bytes 0-%s/*' % upto_bytes,
1375 3dabe5d2 Stavros Sachtouris
            content_type='application/octet-stream',
1376 3dabe5d2 Stavros Sachtouris
            object_bytes=upto_bytes,
1377 bc223d91 Stavros Sachtouris
            source_object=path4url(self.container, obj))
1378 915b99b5 Stavros Sachtouris
        return r.headers
1379 ee62607e Stavros Sachtouris
1380 2005b18e Stavros Sachtouris
    def overwrite_object(self, obj, start, end, source_file, upload_cb=None):
1381 bc223d91 Stavros Sachtouris
        """Overwrite a part of an object from local source file
1382 bc223d91 Stavros Sachtouris

1383 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1384 bc223d91 Stavros Sachtouris

1385 bc223d91 Stavros Sachtouris
        :param start: (int) position in bytes to start overwriting from
1386 bc223d91 Stavros Sachtouris

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

1389 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
1390 bc223d91 Stavros Sachtouris

1391 bc223d91 Stavros Sachtouris
        :param upload_db: progress.bar for uploading
1392 ee62607e Stavros Sachtouris
        """
1393 4067cdaf Stavros Sachtouris
1394 ca092af4 Stavros Sachtouris
        r = self.get_object_info(obj)
1395 ca092af4 Stavros Sachtouris
        rf_size = int(r['content-length'])
1396 ca092af4 Stavros Sachtouris
        if rf_size < int(start):
1397 ca092af4 Stavros Sachtouris
            raise ClientError(
1398 ca092af4 Stavros Sachtouris
                'Range start exceeds file size',
1399 ca092af4 Stavros Sachtouris
                status=416)
1400 ca092af4 Stavros Sachtouris
        elif rf_size < int(end):
1401 ca092af4 Stavros Sachtouris
            raise ClientError(
1402 ca092af4 Stavros Sachtouris
                'Range end exceeds file size',
1403 ca092af4 Stavros Sachtouris
                status=416)
1404 277ca4ed Dionysis Zindros
        self._assert_container()
1405 2f749e6e Stavros Sachtouris
        meta = self.get_container_info()
1406 ee62607e Stavros Sachtouris
        blocksize = int(meta['x-container-block-size'])
1407 64ab4c13 Stavros Sachtouris
        filesize = fstat(source_file.fileno()).st_size
1408 ee62607e Stavros Sachtouris
        datasize = int(end) - int(start) + 1
1409 3dabe5d2 Stavros Sachtouris
        nblocks = 1 + (datasize - 1) // blocksize
1410 ee62607e Stavros Sachtouris
        offset = 0
1411 ca092af4 Stavros Sachtouris
        if upload_cb:
1412 915b99b5 Stavros Sachtouris
            self.progress_bar_gen = upload_cb(nblocks)
1413 915b99b5 Stavros Sachtouris
            self._cb_next()
1414 915b99b5 Stavros Sachtouris
        headers = []
1415 ee62607e Stavros Sachtouris
        for i in range(nblocks):
1416 24ff0a35 Stavros Sachtouris
            read_size = min(blocksize, filesize - offset, datasize - offset)
1417 24ff0a35 Stavros Sachtouris
            block = source_file.read(read_size)
1418 915b99b5 Stavros Sachtouris
            r = self.object_post(
1419 24ff0a35 Stavros Sachtouris
                obj,
1420 3dabe5d2 Stavros Sachtouris
                update=True,
1421 3dabe5d2 Stavros Sachtouris
                content_type='application/octet-stream',
1422 3dabe5d2 Stavros Sachtouris
                content_length=len(block),
1423 ca092af4 Stavros Sachtouris
                content_range='bytes %s-%s/*' % (
1424 ca092af4 Stavros Sachtouris
                    start + offset,
1425 ca092af4 Stavros Sachtouris
                    start + offset + len(block) - 1),
1426 3dabe5d2 Stavros Sachtouris
                data=block)
1427 915b99b5 Stavros Sachtouris
            headers.append(dict(r.headers))
1428 ca092af4 Stavros Sachtouris
            offset += len(block)
1429 3dabe5d2 Stavros Sachtouris
1430 915b99b5 Stavros Sachtouris
            self._cb_next
1431 915b99b5 Stavros Sachtouris
        return headers
1432 7d420701 Stavros Sachtouris
1433 24ff0a35 Stavros Sachtouris
    def copy_object(
1434 2005b18e Stavros Sachtouris
            self, src_container, src_object, dst_container,
1435 33487500 Stavros Sachtouris
            dst_object=None,
1436 2005b18e Stavros Sachtouris
            source_version=None,
1437 3a066af4 Stavros Sachtouris
            source_account=None,
1438 2005b18e Stavros Sachtouris
            public=False,
1439 2005b18e Stavros Sachtouris
            content_type=None,
1440 2005b18e Stavros Sachtouris
            delimiter=None):
1441 bc223d91 Stavros Sachtouris
        """
1442 bc223d91 Stavros Sachtouris
        :param src_container: (str) source container
1443 bc223d91 Stavros Sachtouris

1444 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1445 bc223d91 Stavros Sachtouris

1446 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1447 bc223d91 Stavros Sachtouris

1448 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1449 bc223d91 Stavros Sachtouris

1450 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1451 bc223d91 Stavros Sachtouris

1452 3a066af4 Stavros Sachtouris
        :param source_account: (str) account to copy from
1453 3a066af4 Stavros Sachtouris

1454 bc223d91 Stavros Sachtouris
        :param public: (bool)
1455 bc223d91 Stavros Sachtouris

1456 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1457 bc223d91 Stavros Sachtouris

1458 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1459 55c75058 Stavros Sachtouris

1460 55c75058 Stavros Sachtouris
        :returns: (dict) response headers
1461 bc223d91 Stavros Sachtouris
        """
1462 277ca4ed Dionysis Zindros
        self._assert_account()
1463 7d420701 Stavros Sachtouris
        self.container = dst_container
1464 7d420701 Stavros Sachtouris
        src_path = path4url(src_container, src_object)
1465 55c75058 Stavros Sachtouris
        r = self.object_put(
1466 33487500 Stavros Sachtouris
            dst_object or src_object,
1467 3dabe5d2 Stavros Sachtouris
            success=201,
1468 3dabe5d2 Stavros Sachtouris
            copy_from=src_path,
1469 3dabe5d2 Stavros Sachtouris
            content_length=0,
1470 3dabe5d2 Stavros Sachtouris
            source_version=source_version,
1471 3a066af4 Stavros Sachtouris
            source_account=source_account,
1472 3dabe5d2 Stavros Sachtouris
            public=public,
1473 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
1474 7d420701 Stavros Sachtouris
            delimiter=delimiter)
1475 55c75058 Stavros Sachtouris
        return r.headers
1476 a5e0629d Stavros Sachtouris
1477 24ff0a35 Stavros Sachtouris
    def move_object(
1478 24ff0a35 Stavros Sachtouris
            self, src_container, src_object, dst_container,
1479 24ff0a35 Stavros Sachtouris
            dst_object=False,
1480 4f266635 Stavros Sachtouris
            source_account=None,
1481 24ff0a35 Stavros Sachtouris
            source_version=None,
1482 24ff0a35 Stavros Sachtouris
            public=False,
1483 24ff0a35 Stavros Sachtouris
            content_type=None,
1484 24ff0a35 Stavros Sachtouris
            delimiter=None):
1485 bc223d91 Stavros Sachtouris
        """
1486 bc223d91 Stavros Sachtouris
        :param src_container: (str) source container
1487 bc223d91 Stavros Sachtouris

1488 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1489 bc223d91 Stavros Sachtouris

1490 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1491 bc223d91 Stavros Sachtouris

1492 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1493 bc223d91 Stavros Sachtouris

1494 4f266635 Stavros Sachtouris
        :param source_account: (str) account to move from
1495 4f266635 Stavros Sachtouris

1496 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1497 bc223d91 Stavros Sachtouris

1498 bc223d91 Stavros Sachtouris
        :param public: (bool)
1499 bc223d91 Stavros Sachtouris

1500 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1501 bc223d91 Stavros Sachtouris

1502 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1503 55c75058 Stavros Sachtouris

1504 55c75058 Stavros Sachtouris
        :returns: (dict) response headers
1505 bc223d91 Stavros Sachtouris
        """
1506 277ca4ed Dionysis Zindros
        self._assert_account()
1507 a5e0629d Stavros Sachtouris
        self.container = dst_container
1508 a5e0629d Stavros Sachtouris
        dst_object = dst_object or src_object
1509 a5e0629d Stavros Sachtouris
        src_path = path4url(src_container, src_object)
1510 55c75058 Stavros Sachtouris
        r = self.object_put(
1511 24ff0a35 Stavros Sachtouris
            dst_object,
1512 3dabe5d2 Stavros Sachtouris
            success=201,
1513 3dabe5d2 Stavros Sachtouris
            move_from=src_path,
1514 3dabe5d2 Stavros Sachtouris
            content_length=0,
1515 4f266635 Stavros Sachtouris
            source_account=source_account,
1516 3dabe5d2 Stavros Sachtouris
            source_version=source_version,
1517 3dabe5d2 Stavros Sachtouris
            public=public,
1518 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
1519 a23f6ffe Stavros Sachtouris
            delimiter=delimiter)
1520 55c75058 Stavros Sachtouris
        return r.headers
1521 a23f6ffe Stavros Sachtouris
1522 a23f6ffe Stavros Sachtouris
    def get_sharing_accounts(self, limit=None, marker=None, *args, **kwargs):
1523 bc223d91 Stavros Sachtouris
        """Get accounts that share with self.account
1524 bc223d91 Stavros Sachtouris

1525 bc223d91 Stavros Sachtouris
        :param limit: (str)
1526 bc223d91 Stavros Sachtouris

1527 bc223d91 Stavros Sachtouris
        :param marker: (str)
1528 bc223d91 Stavros Sachtouris

1529 bc223d91 Stavros Sachtouris
        :returns: (dict)
1530 bc223d91 Stavros Sachtouris
        """
1531 277ca4ed Dionysis Zindros
        self._assert_account()
1532 a23f6ffe Stavros Sachtouris
1533 3dabe5d2 Stavros Sachtouris
        self.set_param('format', 'json')
1534 3dabe5d2 Stavros Sachtouris
        self.set_param('limit', limit, iff=limit is not None)
1535 3dabe5d2 Stavros Sachtouris
        self.set_param('marker', marker, iff=marker is not None)
1536 a23f6ffe Stavros Sachtouris
1537 a23f6ffe Stavros Sachtouris
        path = ''
1538 a23f6ffe Stavros Sachtouris
        success = kwargs.pop('success', (200, 204))
1539 3dabe5d2 Stavros Sachtouris
        r = self.get(path, *args, success=success, **kwargs)
1540 38dc5d2f Stavros Sachtouris
        return r.json
1541 38dc5d2f Stavros Sachtouris
1542 bc223d91 Stavros Sachtouris
    def get_object_versionlist(self, obj):
1543 bc223d91 Stavros Sachtouris
        """
1544 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1545 bc223d91 Stavros Sachtouris

1546 bc223d91 Stavros Sachtouris
        :returns: (list)
1547 bc223d91 Stavros Sachtouris
        """
1548 277ca4ed Dionysis Zindros
        self._assert_container()
1549 bc223d91 Stavros Sachtouris
        r = self.object_get(obj, format='json', version='list')
1550 38dc5d2f Stavros Sachtouris
        return r.json['versions']