Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / swiss_army / __init__.py @ d1e7d2b4

History | View | Annotate | Download (13.3 kB)

1 94bff756 Sofia Papagiannaki
# Copyright 2012 GRNET S.A. All rights reserved.
2 94bff756 Sofia Papagiannaki
#
3 94bff756 Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
4 94bff756 Sofia Papagiannaki
# without modification, are permitted provided that the following
5 94bff756 Sofia Papagiannaki
# conditions are met:
6 94bff756 Sofia Papagiannaki
#
7 94bff756 Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
8 94bff756 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
9 94bff756 Sofia Papagiannaki
#      disclaimer.
10 94bff756 Sofia Papagiannaki
#
11 94bff756 Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
12 94bff756 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
13 94bff756 Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
14 94bff756 Sofia Papagiannaki
#      provided with the distribution.
15 94bff756 Sofia Papagiannaki
#
16 94bff756 Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 94bff756 Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 94bff756 Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 94bff756 Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 94bff756 Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 94bff756 Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 94bff756 Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 94bff756 Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 94bff756 Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 94bff756 Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 94bff756 Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 94bff756 Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
28 94bff756 Sofia Papagiannaki
#
29 94bff756 Sofia Papagiannaki
# The views and conclusions contained in the software and
30 94bff756 Sofia Papagiannaki
# documentation are those of the authors and should not be
31 94bff756 Sofia Papagiannaki
# interpreted as representing official policies, either expressed
32 94bff756 Sofia Papagiannaki
# or implied, of GRNET S.A.
33 94bff756 Sofia Papagiannaki
34 94bff756 Sofia Papagiannaki
from pithos.api.util import get_backend, split_container_object_string
35 94bff756 Sofia Papagiannaki
36 94bff756 Sofia Papagiannaki
import re
37 94bff756 Sofia Papagiannaki
import hashlib
38 94bff756 Sofia Papagiannaki
import os
39 94bff756 Sofia Papagiannaki
40 94bff756 Sofia Papagiannaki
41 94bff756 Sofia Papagiannaki
def data_read_iterator(str, size=1024):
42 94bff756 Sofia Papagiannaki
    offset = 0
43 94bff756 Sofia Papagiannaki
    while True:
44 94bff756 Sofia Papagiannaki
        data = str[offset:offset + size]
45 94bff756 Sofia Papagiannaki
        offset = offset + size
46 94bff756 Sofia Papagiannaki
        if not data:
47 94bff756 Sofia Papagiannaki
            break
48 94bff756 Sofia Papagiannaki
        yield data
49 94bff756 Sofia Papagiannaki
50 94bff756 Sofia Papagiannaki
51 94bff756 Sofia Papagiannaki
class SwissArmy():
52 94bff756 Sofia Papagiannaki
    def __init__(self):
53 94bff756 Sofia Papagiannaki
        self.backend = get_backend()
54 94bff756 Sofia Papagiannaki
55 94bff756 Sofia Papagiannaki
    def cleanup(self):
56 94bff756 Sofia Papagiannaki
        self.backend.close()
57 94bff756 Sofia Papagiannaki
58 94bff756 Sofia Papagiannaki
    def existing_accounts(self):
59 d1e7d2b4 Sofia Papagiannaki
        return sorted([path for path, _ in self.backend.node.node_accounts()])
60 94bff756 Sofia Papagiannaki
61 94bff756 Sofia Papagiannaki
    def duplicate_accounts(self):
62 94bff756 Sofia Papagiannaki
        accounts = self.existing_accounts()
63 94bff756 Sofia Papagiannaki
        duplicates = []
64 94bff756 Sofia Papagiannaki
        for i in range(len(accounts)):
65 94bff756 Sofia Papagiannaki
            account = accounts[i]
66 94bff756 Sofia Papagiannaki
            matcher = re.compile(account, re.IGNORECASE)
67 99c11993 Sofia Papagiannaki
            duplicate = filter(matcher.match, (i for i in accounts[i + 1:] \
68 99c11993 Sofia Papagiannaki
                if len(i) == len(account)))
69 94bff756 Sofia Papagiannaki
            if duplicate:
70 94bff756 Sofia Papagiannaki
                duplicate.insert(0, account)
71 94bff756 Sofia Papagiannaki
                duplicates.append(duplicate)
72 94bff756 Sofia Papagiannaki
        return duplicates
73 94bff756 Sofia Papagiannaki
74 94bff756 Sofia Papagiannaki
    def list_all_containers(self, account, step=10):
75 94bff756 Sofia Papagiannaki
        containers = []
76 94bff756 Sofia Papagiannaki
        marker = None
77 94bff756 Sofia Papagiannaki
        while 1:
78 94bff756 Sofia Papagiannaki
            more = self.backend.list_containers(account, account, limit=10,
79 94bff756 Sofia Papagiannaki
                                                marker=marker)
80 94bff756 Sofia Papagiannaki
            if not more:
81 94bff756 Sofia Papagiannaki
                break
82 94bff756 Sofia Papagiannaki
            containers.extend(more)
83 94bff756 Sofia Papagiannaki
            marker = more[-1]
84 94bff756 Sofia Papagiannaki
        return containers
85 94bff756 Sofia Papagiannaki
86 94bff756 Sofia Papagiannaki
    def list_all_container_objects(self, account, container, virtual=False):
87 94bff756 Sofia Papagiannaki
        objects = []
88 94bff756 Sofia Papagiannaki
        marker = None
89 94bff756 Sofia Papagiannaki
        while 1:
90 94bff756 Sofia Papagiannaki
            more = self.backend.list_objects(account, account, container,
91 94bff756 Sofia Papagiannaki
                                             marker=marker, virtual=virtual)
92 94bff756 Sofia Papagiannaki
            if not more:
93 94bff756 Sofia Papagiannaki
                break
94 94bff756 Sofia Papagiannaki
            objects.extend((i[0] for i in more))
95 94bff756 Sofia Papagiannaki
            marker = more[-1][0]
96 94bff756 Sofia Papagiannaki
        return objects
97 94bff756 Sofia Papagiannaki
98 94bff756 Sofia Papagiannaki
    def list_all_objects(self, account, virtual=False):
99 94bff756 Sofia Papagiannaki
        containers = self.list_all_containers(account)
100 94bff756 Sofia Papagiannaki
        objects = []
101 94bff756 Sofia Papagiannaki
        extend = objects.extend
102 94bff756 Sofia Papagiannaki
        for c in containers:
103 94bff756 Sofia Papagiannaki
            more = self.list_all_container_objects(account, c, virtual=virtual)
104 94bff756 Sofia Papagiannaki
            extend([os.path.join(c, i) for i in more])
105 94bff756 Sofia Papagiannaki
        return objects
106 94bff756 Sofia Papagiannaki
107 94bff756 Sofia Papagiannaki
    def list_past_versions(self, account, container, name):
108 94bff756 Sofia Papagiannaki
        versions = self.backend.list_versions(account, account, container,
109 94bff756 Sofia Papagiannaki
                                              name)
110 94bff756 Sofia Papagiannaki
        # do not return the current version
111 94bff756 Sofia Papagiannaki
        return list(x[0] for x in versions[:-1])
112 94bff756 Sofia Papagiannaki
113 94bff756 Sofia Papagiannaki
    def move_object(self, src_account, src_container, src_name,
114 94bff756 Sofia Papagiannaki
                    dest_account, dry=True, silent=False):
115 99c11993 Sofia Papagiannaki
        if src_account not in self.existing_accounts():
116 99c11993 Sofia Papagiannaki
            raise NameError('%s does not exist' % src_account)
117 99c11993 Sofia Papagiannaki
        if dest_account not in self.existing_accounts():
118 99c11993 Sofia Papagiannaki
            raise NameError('%s does not exist' % dest_account)
119 94bff756 Sofia Papagiannaki
120 94bff756 Sofia Papagiannaki
        trans = self.backend.wrapper.conn.begin()
121 94bff756 Sofia Papagiannaki
        try:
122 99c11993 Sofia Papagiannaki
            self._copy_object(src_account, src_container, src_name,
123 99c11993 Sofia Papagiannaki
                              dest_account, move=True)
124 94bff756 Sofia Papagiannaki
125 94bff756 Sofia Papagiannaki
            if dry:
126 94bff756 Sofia Papagiannaki
                if not silent:
127 94bff756 Sofia Papagiannaki
                    print "Skipping database commit."
128 94bff756 Sofia Papagiannaki
                trans.rollback()
129 94bff756 Sofia Papagiannaki
            else:
130 94bff756 Sofia Papagiannaki
                trans.commit()
131 94bff756 Sofia Papagiannaki
                if not silent:
132 94bff756 Sofia Papagiannaki
                    print "%s is deleted." % src_account
133 94bff756 Sofia Papagiannaki
        except:
134 94bff756 Sofia Papagiannaki
            trans.rollback()
135 94bff756 Sofia Papagiannaki
            raise
136 94bff756 Sofia Papagiannaki
137 99c11993 Sofia Papagiannaki
    def _copy_object(self, src_account, src_container, src_name,
138 99c11993 Sofia Papagiannaki
                    dest_account, move=False):
139 94bff756 Sofia Papagiannaki
        path = os.path.join(src_container, src_name)
140 94bff756 Sofia Papagiannaki
        fullpath = os.path.join(src_account, path)
141 94bff756 Sofia Papagiannaki
        dest_container = src_container
142 94bff756 Sofia Papagiannaki
        dest_name = src_name
143 94bff756 Sofia Papagiannaki
144 94bff756 Sofia Papagiannaki
        meta = self.backend.get_object_meta(src_account, src_account,
145 94bff756 Sofia Papagiannaki
                                            src_container, src_name, 'pithos',
146 94bff756 Sofia Papagiannaki
                                            version=None)
147 94bff756 Sofia Papagiannaki
        content_type = meta.get('type')
148 94bff756 Sofia Papagiannaki
149 94bff756 Sofia Papagiannaki
        # get source object history
150 94bff756 Sofia Papagiannaki
        versions = self.list_past_versions(src_account, src_container,
151 94bff756 Sofia Papagiannaki
                                           src_name)
152 94bff756 Sofia Papagiannaki
153 94bff756 Sofia Papagiannaki
        # get source object permissions
154 94bff756 Sofia Papagiannaki
        permissions = self.backend.permissions.access_get(fullpath)
155 94bff756 Sofia Papagiannaki
156 94bff756 Sofia Papagiannaki
        # get source object public
157 94bff756 Sofia Papagiannaki
        public = self.backend.get_object_public(src_account, src_account,
158 94bff756 Sofia Papagiannaki
                                                src_container, src_name)
159 94bff756 Sofia Papagiannaki
160 94bff756 Sofia Papagiannaki
        if dest_container in self.backend.list_containers(dest_account,
161 94bff756 Sofia Papagiannaki
                                                          dest_account):
162 94bff756 Sofia Papagiannaki
            # Note: if dest_container contains an object with the same name
163 94bff756 Sofia Papagiannaki
            # a new version with the contents of the source object will be
164 94bff756 Sofia Papagiannaki
            # created and the one in the destination container will pass to
165 94bff756 Sofia Papagiannaki
            # history
166 94bff756 Sofia Papagiannaki
            self.backend.copy_object(dest_account, src_account, src_container,
167 94bff756 Sofia Papagiannaki
                                     src_name, dest_account, dest_container,
168 94bff756 Sofia Papagiannaki
                                     dest_name, content_type, 'pithos',
169 94bff756 Sofia Papagiannaki
                                     meta={}, replace_meta=False,
170 94bff756 Sofia Papagiannaki
                                     permissions=permissions)
171 94bff756 Sofia Papagiannaki
        else:
172 94bff756 Sofia Papagiannaki
            # create destination container and retry
173 94bff756 Sofia Papagiannaki
            self.backend.put_container(dest_account, dest_account,
174 94bff756 Sofia Papagiannaki
                                       dest_container)
175 94bff756 Sofia Papagiannaki
            self.backend.copy_object(dest_account, src_account, src_container,
176 94bff756 Sofia Papagiannaki
                                     src_name, dest_account, dest_container,
177 94bff756 Sofia Papagiannaki
                                     dest_name, content_type, 'pithos',
178 94bff756 Sofia Papagiannaki
                                     meta={}, replace_meta=False,
179 94bff756 Sofia Papagiannaki
                                     permissions=permissions)
180 94bff756 Sofia Papagiannaki
181 99c11993 Sofia Papagiannaki
        if move:
182 99c11993 Sofia Papagiannaki
            self.backend.delete_object(src_account, src_account,
183 99c11993 Sofia Papagiannaki
                                       src_container, src_name)
184 94bff756 Sofia Papagiannaki
185 94bff756 Sofia Papagiannaki
        dest_path, dest_node = self.backend._lookup_object(dest_account,
186 94bff756 Sofia Papagiannaki
                                                           dest_container,
187 94bff756 Sofia Papagiannaki
                                                           dest_name)
188 94bff756 Sofia Papagiannaki
        assert dest_path == '/'.join([dest_account, path])
189 94bff756 Sofia Papagiannaki
190 94bff756 Sofia Papagiannaki
        # turn history versions to point to the newly created node
191 94bff756 Sofia Papagiannaki
        for serial in versions:
192 94bff756 Sofia Papagiannaki
            self.backend.node.version_put_property(serial, 'node', dest_node)
193 94bff756 Sofia Papagiannaki
194 94bff756 Sofia Papagiannaki
        if public:
195 94bff756 Sofia Papagiannaki
            # set destination object public
196 94bff756 Sofia Papagiannaki
            fullpath = '/'.join([dest_account, dest_container, dest_name])
197 56f3c759 Sofia Papagiannaki
            self.backend.permissions.public_set(
198 56f3c759 Sofia Papagiannaki
                fullpath,
199 4a105ce2 Sofia Papagiannaki
                self.backend.public_url_security,
200 56f3c759 Sofia Papagiannaki
                self.backend.public_url_alphabet
201 56f3c759 Sofia Papagiannaki
            )
202 94bff756 Sofia Papagiannaki
203 99c11993 Sofia Papagiannaki
    def _merge_account(self, src_account, dest_account, delete_src=False):
204 94bff756 Sofia Papagiannaki
            # TODO: handle exceptions
205 94bff756 Sofia Papagiannaki
            # copy all source objects
206 94bff756 Sofia Papagiannaki
            for path in self.list_all_objects(src_account):
207 94bff756 Sofia Papagiannaki
                src_container, src_name = split_container_object_string(
208 94bff756 Sofia Papagiannaki
                    '/%s' % path)
209 94bff756 Sofia Papagiannaki
210 94bff756 Sofia Papagiannaki
                # give read permissions to the dest_account
211 99c11993 Sofia Papagiannaki
                permissions = self.backend.get_object_permissions(
212 94bff756 Sofia Papagiannaki
                    src_account, src_account, src_container, src_name)
213 94bff756 Sofia Papagiannaki
                if permissions:
214 94bff756 Sofia Papagiannaki
                    permissions = permissions[2]
215 94bff756 Sofia Papagiannaki
                permissions['read'] = permissions.get('read', [])
216 94bff756 Sofia Papagiannaki
                permissions['read'].append(dest_account)
217 94bff756 Sofia Papagiannaki
                self.backend.update_object_permissions(src_account,
218 94bff756 Sofia Papagiannaki
                                                       src_account,
219 94bff756 Sofia Papagiannaki
                                                       src_container,
220 94bff756 Sofia Papagiannaki
                                                       src_name,
221 94bff756 Sofia Papagiannaki
                                                       permissions)
222 94bff756 Sofia Papagiannaki
223 99c11993 Sofia Papagiannaki
                self._copy_object(src_account, src_container, src_name,
224 99c11993 Sofia Papagiannaki
                                 dest_account, move=delete_src)
225 94bff756 Sofia Papagiannaki
226 94bff756 Sofia Papagiannaki
            # move groups also
227 94bff756 Sofia Papagiannaki
            groups = self.backend.get_account_groups(src_account, src_account)
228 94bff756 Sofia Papagiannaki
            (v.replace(src_account, dest_account) for v in groups.values())
229 94bff756 Sofia Papagiannaki
            self.backend.update_account_groups(dest_account, dest_account,
230 94bff756 Sofia Papagiannaki
                                               groups)
231 99c11993 Sofia Papagiannaki
            if delete_src:
232 99c11993 Sofia Papagiannaki
                self._delete_account(src_account)
233 94bff756 Sofia Papagiannaki
234 94bff756 Sofia Papagiannaki
    def merge_account(self, src_account, dest_account, only_stats=True,
235 99c11993 Sofia Papagiannaki
                      dry=True, silent=False, delete_src=False):
236 99c11993 Sofia Papagiannaki
        if src_account not in self.existing_accounts():
237 99c11993 Sofia Papagiannaki
            raise NameError('%s does not exist' % src_account)
238 99c11993 Sofia Papagiannaki
        if dest_account not in self.existing_accounts():
239 99c11993 Sofia Papagiannaki
            raise NameError('%s does not exist' % dest_account)
240 99c11993 Sofia Papagiannaki
241 94bff756 Sofia Papagiannaki
        if only_stats:
242 94bff756 Sofia Papagiannaki
            print "The following %s's entries will be moved to %s:" \
243 94bff756 Sofia Papagiannaki
                % (src_account, dest_account)
244 94bff756 Sofia Papagiannaki
            print "Objects: %r" % self.list_all_objects(src_account)
245 94bff756 Sofia Papagiannaki
            print "Groups: %r" \
246 94bff756 Sofia Papagiannaki
                % self.backend.get_account_groups(src_account,
247 94bff756 Sofia Papagiannaki
                                                  src_account).keys()
248 94bff756 Sofia Papagiannaki
            return
249 94bff756 Sofia Papagiannaki
250 94bff756 Sofia Papagiannaki
        trans = self.backend.wrapper.conn.begin()
251 94bff756 Sofia Papagiannaki
        try:
252 99c11993 Sofia Papagiannaki
            self._merge_account(src_account, dest_account, delete_src)
253 94bff756 Sofia Papagiannaki
254 94bff756 Sofia Papagiannaki
            if dry:
255 94bff756 Sofia Papagiannaki
                if not silent:
256 94bff756 Sofia Papagiannaki
                    print "Skipping database commit."
257 94bff756 Sofia Papagiannaki
                trans.rollback()
258 94bff756 Sofia Papagiannaki
            else:
259 94bff756 Sofia Papagiannaki
                trans.commit()
260 94bff756 Sofia Papagiannaki
                if not silent:
261 99c11993 Sofia Papagiannaki
                    msg = "%s merged into %s."
262 94bff756 Sofia Papagiannaki
                    print msg % (src_account, dest_account)
263 94bff756 Sofia Papagiannaki
        except:
264 94bff756 Sofia Papagiannaki
            trans.rollback()
265 94bff756 Sofia Papagiannaki
            raise
266 94bff756 Sofia Papagiannaki
267 94bff756 Sofia Papagiannaki
    def delete_container_contents(self, account, container):
268 94bff756 Sofia Papagiannaki
        self.backend.delete_container(account, account, container,
269 94bff756 Sofia Papagiannaki
                                      delimiter='/')
270 94bff756 Sofia Papagiannaki
271 94bff756 Sofia Papagiannaki
    def delete_container(self, account, container):
272 94bff756 Sofia Papagiannaki
        self.backend.delete_container(account, account, container)
273 94bff756 Sofia Papagiannaki
274 94bff756 Sofia Papagiannaki
    def _delete_account(self, account):
275 94bff756 Sofia Papagiannaki
        for c in self.list_all_containers(account):
276 94bff756 Sofia Papagiannaki
            self.delete_container_contents(account, c)
277 94bff756 Sofia Papagiannaki
            self.delete_container(account, c)
278 94bff756 Sofia Papagiannaki
        self.backend.delete_account(account, account)
279 94bff756 Sofia Papagiannaki
280 94bff756 Sofia Papagiannaki
    def delete_account(self, account, only_stats=True, dry=True, silent=False):
281 99c11993 Sofia Papagiannaki
        if account not in self.existing_accounts():
282 99c11993 Sofia Papagiannaki
            raise NameError('%s does not exist' % account)
283 94bff756 Sofia Papagiannaki
        if only_stats:
284 94bff756 Sofia Papagiannaki
            print "The following %s's entries will be removed:" % account
285 94bff756 Sofia Papagiannaki
            print "Objects: %r" % self.list_all_objects(account)
286 94bff756 Sofia Papagiannaki
            print "Groups: %r" \
287 94bff756 Sofia Papagiannaki
                % self.backend.get_account_groups(account, account).keys()
288 94bff756 Sofia Papagiannaki
            return
289 94bff756 Sofia Papagiannaki
290 94bff756 Sofia Papagiannaki
        trans = self.backend.wrapper.conn.begin()
291 94bff756 Sofia Papagiannaki
        try:
292 94bff756 Sofia Papagiannaki
            self._delete_account(account)
293 94bff756 Sofia Papagiannaki
294 94bff756 Sofia Papagiannaki
            if dry:
295 94bff756 Sofia Papagiannaki
                if not silent:
296 94bff756 Sofia Papagiannaki
                    print "Skipping database commit."
297 94bff756 Sofia Papagiannaki
                trans.rollback()
298 94bff756 Sofia Papagiannaki
            else:
299 94bff756 Sofia Papagiannaki
                trans.commit()
300 94bff756 Sofia Papagiannaki
                if not silent:
301 94bff756 Sofia Papagiannaki
                    print "%s is deleted." % account
302 94bff756 Sofia Papagiannaki
        except:
303 94bff756 Sofia Papagiannaki
            trans.rollback()
304 94bff756 Sofia Papagiannaki
            raise
305 94bff756 Sofia Papagiannaki
306 94bff756 Sofia Papagiannaki
    def create_account(self, account):
307 94bff756 Sofia Papagiannaki
        return self.backend._lookup_account(account, create=True)
308 94bff756 Sofia Papagiannaki
309 94bff756 Sofia Papagiannaki
    def create_update_object(self, account, container, name, content_type,
310 78348987 Sofia Papagiannaki
                             data, meta=None, permissions=None, request_user=None):
311 78348987 Sofia Papagiannaki
        meta = meta or {}
312 78348987 Sofia Papagiannaki
        permissions = permissions or {}
313 94bff756 Sofia Papagiannaki
        md5 = hashlib.md5()
314 94bff756 Sofia Papagiannaki
        size = 0
315 94bff756 Sofia Papagiannaki
        hashmap = []
316 94bff756 Sofia Papagiannaki
        for block_data in data_read_iterator(data, self.backend.block_size):
317 94bff756 Sofia Papagiannaki
            size += len(block_data)
318 94bff756 Sofia Papagiannaki
            hashmap.append(self.backend.put_block(block_data))
319 94bff756 Sofia Papagiannaki
            md5.update(block_data)
320 94bff756 Sofia Papagiannaki
321 94bff756 Sofia Papagiannaki
        checksum = md5.hexdigest().lower()
322 94bff756 Sofia Papagiannaki
323 94bff756 Sofia Papagiannaki
        request_user = request_user or account
324 94bff756 Sofia Papagiannaki
        return self.backend.update_object_hashmap(request_user, account,
325 94bff756 Sofia Papagiannaki
                                                  container, name, size,
326 94bff756 Sofia Papagiannaki
                                                  content_type, hashmap,
327 94bff756 Sofia Papagiannaki
                                                  checksum, 'pithos', meta,
328 94bff756 Sofia Papagiannaki
                                                  True, permissions)