Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / pithos / __init__.py @ 36fa6ffb

History | View | Annotate | Download (49.4 kB)

1 fce31e83 Stavros Sachtouris
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 d2cea1e2 Giorgos Verigakis
#
3 d2cea1e2 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 d2cea1e2 Giorgos Verigakis
# without modification, are permitted provided that the following
5 d2cea1e2 Giorgos Verigakis
# conditions are met:
6 d2cea1e2 Giorgos Verigakis
#
7 d2cea1e2 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 d2cea1e2 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 d2cea1e2 Giorgos Verigakis
#      disclaimer.
10 d2cea1e2 Giorgos Verigakis
#
11 d2cea1e2 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 d2cea1e2 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 d2cea1e2 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 d2cea1e2 Giorgos Verigakis
#      provided with the distribution.
15 d2cea1e2 Giorgos Verigakis
#
16 d2cea1e2 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 d2cea1e2 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 d2cea1e2 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 d2cea1e2 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 d2cea1e2 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 d2cea1e2 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 d2cea1e2 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 d2cea1e2 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 d2cea1e2 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 d2cea1e2 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 d2cea1e2 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 d2cea1e2 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 d2cea1e2 Giorgos Verigakis
#
29 d2cea1e2 Giorgos Verigakis
# The views and conclusions contained in the software and
30 d2cea1e2 Giorgos Verigakis
# documentation are those of the authors and should not be
31 d2cea1e2 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 d2cea1e2 Giorgos Verigakis
# or implied, of GRNET S.A.
33 d2cea1e2 Giorgos Verigakis
34 f27ed9a0 Stavros Sachtouris
from threading import enumerate as activethreads
35 435008b6 Stavros Sachtouris
36 3dabe5d2 Stavros Sachtouris
from os import fstat
37 64ab4c13 Stavros Sachtouris
from hashlib import new as newhashlib
38 e02728f9 Stavros Sachtouris
from time import time
39 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 6e6b6117 Stavros Sachtouris
        """Delete an empty container and destroy associated blocks"""
136 2a7292f1 Stavros Sachtouris
        cnt_back_up = self.container
137 2a7292f1 Stavros Sachtouris
        try:
138 2a7292f1 Stavros Sachtouris
            self.container = container or cnt_back_up
139 5655d560 Stavros Sachtouris
            r = self.container_delete(until=unicode(time()))
140 2a7292f1 Stavros Sachtouris
        finally:
141 2a7292f1 Stavros Sachtouris
            self.container = cnt_back_up
142 5655d560 Stavros Sachtouris
        return r.headers
143 3dabe5d2 Stavros Sachtouris
144 24ff0a35 Stavros Sachtouris
    def upload_object_unchunked(
145 24ff0a35 Stavros Sachtouris
            self, obj, f,
146 24ff0a35 Stavros Sachtouris
            withHashFile=False,
147 24ff0a35 Stavros Sachtouris
            size=None,
148 24ff0a35 Stavros Sachtouris
            etag=None,
149 24ff0a35 Stavros Sachtouris
            content_encoding=None,
150 24ff0a35 Stavros Sachtouris
            content_disposition=None,
151 24ff0a35 Stavros Sachtouris
            content_type=None,
152 24ff0a35 Stavros Sachtouris
            sharing=None,
153 24ff0a35 Stavros Sachtouris
            public=None):
154 4375e020 Stavros Sachtouris
        """
155 4375e020 Stavros Sachtouris
        :param obj: (str) remote object path
156 4375e020 Stavros Sachtouris

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

420 76ebf97c Stavros Sachtouris
        :param container_info_cache: (dict) if given, avoid redundant calls to
421 9dc6159f Stavros Sachtouris
            server for container info (block size and hash information)
422 4375e020 Stavros Sachtouris
        """
423 277ca4ed Dionysis Zindros
        self._assert_container()
424 56f0908a Stavros Sachtouris
425 14c72dbd Stavros Sachtouris
        block_info = (
426 14c72dbd Stavros Sachtouris
            blocksize, blockhash, size, nblocks) = self._get_file_block_info(
427 14c72dbd Stavros Sachtouris
                f, size, container_info_cache)
428 64ab4c13 Stavros Sachtouris
        (hashes, hmap, offset) = ([], {}, 0)
429 8df239df Stavros Sachtouris
        content_type = content_type or '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 8b4ba753 Stavros Sachtouris
                raise ClientError('%s blocks failed to upload' % len(missing))
622 f27ed9a0 Stavros Sachtouris
        except KeyboardInterrupt:
623 6069b53b Stavros Sachtouris
            sendlog.info('- - - wait for threads to finish')
624 f27ed9a0 Stavros Sachtouris
            for thread in activethreads():
625 f27ed9a0 Stavros Sachtouris
                thread.join()
626 f27ed9a0 Stavros Sachtouris
            raise
627 36fa6ffb Stavros Sachtouris
        self._cb_next()
628 f27ed9a0 Stavros Sachtouris
629 3c216009 Stavros Sachtouris
        r = self.object_put(
630 f27ed9a0 Stavros Sachtouris
            obj,
631 3dabe5d2 Stavros Sachtouris
            format='json',
632 3dabe5d2 Stavros Sachtouris
            hashmap=True,
633 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
634 5c2058e7 Stavros Sachtouris
            content_encoding=content_encoding,
635 e9ac514e Stavros Sachtouris
            if_etag_match=if_etag_match,
636 524d9cdd Stavros Sachtouris
            if_etag_not_match='*' if if_not_exist else None,
637 524d9cdd Stavros Sachtouris
            etag=etag,
638 3dabe5d2 Stavros Sachtouris
            json=hashmap,
639 50165863 Stavros Sachtouris
            permissions=sharing,
640 50165863 Stavros Sachtouris
            public=public,
641 3dabe5d2 Stavros Sachtouris
            success=201)
642 3c216009 Stavros Sachtouris
        return r.headers
643 3dabe5d2 Stavros Sachtouris
644 f27ed9a0 Stavros Sachtouris
    # download_* auxiliary methods
645 fbfee225 Stavros Sachtouris
    def _get_remote_blocks_info(self, obj, **restargs):
646 56f0908a Stavros Sachtouris
        #retrieve object hashmap
647 3dabe5d2 Stavros Sachtouris
        myrange = restargs.pop('data_range', None)
648 319be41b Stavros Sachtouris
        hashmap = self.get_object_hashmap(obj, **restargs)
649 642f1bbd Stavros Sachtouris
        restargs['data_range'] = myrange
650 56f0908a Stavros Sachtouris
        blocksize = int(hashmap['block_size'])
651 56f0908a Stavros Sachtouris
        blockhash = hashmap['block_hash']
652 56f0908a Stavros Sachtouris
        total_size = hashmap['bytes']
653 fbfee225 Stavros Sachtouris
        #assert total_size/blocksize + 1 == len(hashmap['hashes'])
654 56f0908a Stavros Sachtouris
        map_dict = {}
655 fbfee225 Stavros Sachtouris
        for i, h in enumerate(hashmap['hashes']):
656 ca7f78c0 Stavros Sachtouris
            #  map_dict[h] = i   CHAGE
657 ca7f78c0 Stavros Sachtouris
            if h in map_dict:
658 ca7f78c0 Stavros Sachtouris
                map_dict[h].append(i)
659 ca7f78c0 Stavros Sachtouris
            else:
660 ca7f78c0 Stavros Sachtouris
                map_dict[h] = [i]
661 fbfee225 Stavros Sachtouris
        return (blocksize, blockhash, total_size, hashmap['hashes'], map_dict)
662 64ab4c13 Stavros Sachtouris
663 24ff0a35 Stavros Sachtouris
    def _dump_blocks_sync(
664 7806f19d Stavros Sachtouris
            self, obj, remote_hashes, blocksize, total_size, dst, crange,
665 24ff0a35 Stavros Sachtouris
            **args):
666 edc1182f Stavros Sachtouris
        if not total_size:
667 edc1182f Stavros Sachtouris
            return
668 fbfee225 Stavros Sachtouris
        for blockid, blockhash in enumerate(remote_hashes):
669 24ff0a35 Stavros Sachtouris
            if blockhash:
670 24ff0a35 Stavros Sachtouris
                start = blocksize * blockid
671 24ff0a35 Stavros Sachtouris
                is_last = start + blocksize > total_size
672 24ff0a35 Stavros Sachtouris
                end = (total_size - 1) if is_last else (start + blocksize - 1)
673 776b275c Stavros Sachtouris
                data_range = _range_up(start, end, total_size, crange)
674 776b275c Stavros Sachtouris
                if not data_range:
675 776b275c Stavros Sachtouris
                    self._cb_next()
676 776b275c Stavros Sachtouris
                    continue
677 776b275c Stavros Sachtouris
                args['data_range'] = 'bytes=%s' % data_range
678 24ff0a35 Stavros Sachtouris
                r = self.object_get(obj, success=(200, 206), **args)
679 24ff0a35 Stavros Sachtouris
                self._cb_next()
680 24ff0a35 Stavros Sachtouris
                dst.write(r.content)
681 24ff0a35 Stavros Sachtouris
                dst.flush()
682 fbfee225 Stavros Sachtouris
683 24ff0a35 Stavros Sachtouris
    def _get_block_async(self, obj, **args):
684 24ff0a35 Stavros Sachtouris
        event = SilentEvent(self.object_get, obj, success=(200, 206), **args)
685 e02728f9 Stavros Sachtouris
        event.start()
686 e02728f9 Stavros Sachtouris
        return event
687 fb0cd49a Stavros Sachtouris
688 48c3782c Stavros Sachtouris
    def _hash_from_file(self, fp, start, size, blockhash):
689 48c3782c Stavros Sachtouris
        fp.seek(start)
690 4f228300 Stavros Sachtouris
        block = readall(fp, size)
691 48c3782c Stavros Sachtouris
        h = newhashlib(blockhash)
692 48c3782c Stavros Sachtouris
        h.update(block.strip('\x00'))
693 48c3782c Stavros Sachtouris
        return hexlify(h.digest())
694 48c3782c Stavros Sachtouris
695 28cbc3c2 Stavros Sachtouris
    def _thread2file(self, flying, blockids, local_file, offset=0, **restargs):
696 22fc09fb Stavros Sachtouris
        """write the results of a greenleted rest call to a file
697 f5f2dc53 Stavros Sachtouris

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1183 4375e020 Stavros Sachtouris
        :param until: (str) formated date
1184 4375e020 Stavros Sachtouris

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

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

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

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

1234 bc223d91 Stavros Sachtouris
        :param version: (str)
1235 bc223d91 Stavros Sachtouris

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

1250 bc223d91 Stavros Sachtouris
        :param version: (str)
1251 bc223d91 Stavros Sachtouris

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

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

1285 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1286 bc223d91 Stavros Sachtouris

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

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

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

1312 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
1313 f49084df Stavros Sachtouris

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

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

1372 915b99b5 Stavros Sachtouris
        :returns: (dict) response headers
1373 bc223d91 Stavros Sachtouris
        """
1374 b5b4441e Stavros Sachtouris
        ctype = self.get_object_info(obj)['content-type']
1375 915b99b5 Stavros Sachtouris
        r = self.object_post(
1376 24ff0a35 Stavros Sachtouris
            obj,
1377 3dabe5d2 Stavros Sachtouris
            update=True,
1378 3dabe5d2 Stavros Sachtouris
            content_range='bytes 0-%s/*' % upto_bytes,
1379 b5b4441e Stavros Sachtouris
            content_type=ctype,
1380 3dabe5d2 Stavros Sachtouris
            object_bytes=upto_bytes,
1381 bc223d91 Stavros Sachtouris
            source_object=path4url(self.container, obj))
1382 915b99b5 Stavros Sachtouris
        return r.headers
1383 ee62607e Stavros Sachtouris
1384 614a20dc Stavros Sachtouris
    def overwrite_object(
1385 614a20dc Stavros Sachtouris
            self, obj, start, end, source_file,
1386 f5ea3023 Stavros Sachtouris
            source_version=None, upload_cb=None):
1387 bc223d91 Stavros Sachtouris
        """Overwrite a part of an object from local source file
1388 38a79780 Stavros Sachtouris
        ATTENTION: content_type must always be application/octet-stream
1389 bc223d91 Stavros Sachtouris

1390 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1391 bc223d91 Stavros Sachtouris

1392 bc223d91 Stavros Sachtouris
        :param start: (int) position in bytes to start overwriting from
1393 bc223d91 Stavros Sachtouris

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

1396 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
1397 bc223d91 Stavros Sachtouris

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

1447 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1448 bc223d91 Stavros Sachtouris

1449 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1450 bc223d91 Stavros Sachtouris

1451 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1452 bc223d91 Stavros Sachtouris

1453 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1454 bc223d91 Stavros Sachtouris

1455 3a066af4 Stavros Sachtouris
        :param source_account: (str) account to copy from
1456 3a066af4 Stavros Sachtouris

1457 bc223d91 Stavros Sachtouris
        :param public: (bool)
1458 bc223d91 Stavros Sachtouris

1459 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1460 bc223d91 Stavros Sachtouris

1461 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1462 55c75058 Stavros Sachtouris

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

1491 bc223d91 Stavros Sachtouris
        :param src_object: (str) source object path
1492 bc223d91 Stavros Sachtouris

1493 bc223d91 Stavros Sachtouris
        :param dst_container: (str) destination container
1494 bc223d91 Stavros Sachtouris

1495 bc223d91 Stavros Sachtouris
        :param dst_object: (str) destination object path
1496 bc223d91 Stavros Sachtouris

1497 4f266635 Stavros Sachtouris
        :param source_account: (str) account to move from
1498 4f266635 Stavros Sachtouris

1499 bc223d91 Stavros Sachtouris
        :param source_version: (str) source object version
1500 bc223d91 Stavros Sachtouris

1501 bc223d91 Stavros Sachtouris
        :param public: (bool)
1502 bc223d91 Stavros Sachtouris

1503 bc223d91 Stavros Sachtouris
        :param content_type: (str)
1504 bc223d91 Stavros Sachtouris

1505 bc223d91 Stavros Sachtouris
        :param delimiter: (str)
1506 55c75058 Stavros Sachtouris

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

1528 bc223d91 Stavros Sachtouris
        :param limit: (str)
1529 bc223d91 Stavros Sachtouris

1530 bc223d91 Stavros Sachtouris
        :param marker: (str)
1531 bc223d91 Stavros Sachtouris

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

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