Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / pithos / __init__.py @ 8df239df

History | View | Annotate | Download (49.3 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 f27ed9a0 Stavros Sachtouris
628 3c216009 Stavros Sachtouris
        r = self.object_put(
629 f27ed9a0 Stavros Sachtouris
            obj,
630 3dabe5d2 Stavros Sachtouris
            format='json',
631 3dabe5d2 Stavros Sachtouris
            hashmap=True,
632 3dabe5d2 Stavros Sachtouris
            content_type=content_type,
633 5c2058e7 Stavros Sachtouris
            content_encoding=content_encoding,
634 e9ac514e Stavros Sachtouris
            if_etag_match=if_etag_match,
635 524d9cdd Stavros Sachtouris
            if_etag_not_match='*' if if_not_exist else None,
636 524d9cdd Stavros Sachtouris
            etag=etag,
637 3dabe5d2 Stavros Sachtouris
            json=hashmap,
638 50165863 Stavros Sachtouris
            permissions=sharing,
639 50165863 Stavros Sachtouris
            public=public,
640 3dabe5d2 Stavros Sachtouris
            success=201)
641 3c216009 Stavros Sachtouris
        return r.headers
642 3dabe5d2 Stavros Sachtouris
643 f27ed9a0 Stavros Sachtouris
    # download_* auxiliary methods
644 fbfee225 Stavros Sachtouris
    def _get_remote_blocks_info(self, obj, **restargs):
645 56f0908a Stavros Sachtouris
        #retrieve object hashmap
646 3dabe5d2 Stavros Sachtouris
        myrange = restargs.pop('data_range', None)
647 319be41b Stavros Sachtouris
        hashmap = self.get_object_hashmap(obj, **restargs)
648 642f1bbd Stavros Sachtouris
        restargs['data_range'] = myrange
649 56f0908a Stavros Sachtouris
        blocksize = int(hashmap['block_size'])
650 56f0908a Stavros Sachtouris
        blockhash = hashmap['block_hash']
651 56f0908a Stavros Sachtouris
        total_size = hashmap['bytes']
652 fbfee225 Stavros Sachtouris
        #assert total_size/blocksize + 1 == len(hashmap['hashes'])
653 56f0908a Stavros Sachtouris
        map_dict = {}
654 fbfee225 Stavros Sachtouris
        for i, h in enumerate(hashmap['hashes']):
655 ca7f78c0 Stavros Sachtouris
            #  map_dict[h] = i   CHAGE
656 ca7f78c0 Stavros Sachtouris
            if h in map_dict:
657 ca7f78c0 Stavros Sachtouris
                map_dict[h].append(i)
658 ca7f78c0 Stavros Sachtouris
            else:
659 ca7f78c0 Stavros Sachtouris
                map_dict[h] = [i]
660 fbfee225 Stavros Sachtouris
        return (blocksize, blockhash, total_size, hashmap['hashes'], map_dict)
661 64ab4c13 Stavros Sachtouris
662 24ff0a35 Stavros Sachtouris
    def _dump_blocks_sync(
663 7806f19d Stavros Sachtouris
            self, obj, remote_hashes, blocksize, total_size, dst, crange,
664 24ff0a35 Stavros Sachtouris
            **args):
665 edc1182f Stavros Sachtouris
        if not total_size:
666 edc1182f Stavros Sachtouris
            return
667 fbfee225 Stavros Sachtouris
        for blockid, blockhash in enumerate(remote_hashes):
668 24ff0a35 Stavros Sachtouris
            if blockhash:
669 24ff0a35 Stavros Sachtouris
                start = blocksize * blockid
670 24ff0a35 Stavros Sachtouris
                is_last = start + blocksize > total_size
671 24ff0a35 Stavros Sachtouris
                end = (total_size - 1) if is_last else (start + blocksize - 1)
672 776b275c Stavros Sachtouris
                data_range = _range_up(start, end, total_size, crange)
673 776b275c Stavros Sachtouris
                if not data_range:
674 776b275c Stavros Sachtouris
                    self._cb_next()
675 776b275c Stavros Sachtouris
                    continue
676 776b275c Stavros Sachtouris
                args['data_range'] = 'bytes=%s' % data_range
677 24ff0a35 Stavros Sachtouris
                r = self.object_get(obj, success=(200, 206), **args)
678 24ff0a35 Stavros Sachtouris
                self._cb_next()
679 24ff0a35 Stavros Sachtouris
                dst.write(r.content)
680 24ff0a35 Stavros Sachtouris
                dst.flush()
681 fbfee225 Stavros Sachtouris
682 24ff0a35 Stavros Sachtouris
    def _get_block_async(self, obj, **args):
683 24ff0a35 Stavros Sachtouris
        event = SilentEvent(self.object_get, obj, success=(200, 206), **args)
684 e02728f9 Stavros Sachtouris
        event.start()
685 e02728f9 Stavros Sachtouris
        return event
686 fb0cd49a Stavros Sachtouris
687 48c3782c Stavros Sachtouris
    def _hash_from_file(self, fp, start, size, blockhash):
688 48c3782c Stavros Sachtouris
        fp.seek(start)
689 4f228300 Stavros Sachtouris
        block = readall(fp, size)
690 48c3782c Stavros Sachtouris
        h = newhashlib(blockhash)
691 48c3782c Stavros Sachtouris
        h.update(block.strip('\x00'))
692 48c3782c Stavros Sachtouris
        return hexlify(h.digest())
693 48c3782c Stavros Sachtouris
694 28cbc3c2 Stavros Sachtouris
    def _thread2file(self, flying, blockids, local_file, offset=0, **restargs):
695 22fc09fb Stavros Sachtouris
        """write the results of a greenleted rest call to a file
696 f5f2dc53 Stavros Sachtouris

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1388 bc223d91 Stavros Sachtouris
        :param obj: (str) remote object path
1389 bc223d91 Stavros Sachtouris

1390 bc223d91 Stavros Sachtouris
        :param start: (int) position in bytes to start overwriting from
1391 bc223d91 Stavros Sachtouris

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

1394 bc223d91 Stavros Sachtouris
        :param source_file: open file descriptor
1395 bc223d91 Stavros Sachtouris

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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