Statistics
| Branch: | Tag: | Revision:

root / snf-app / synnefo / plankton / backend.py @ bfd9f988

History | View | Annotate | Download (15.4 kB)

1 c34de90f Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 c34de90f Giorgos Verigakis
#
3 c34de90f Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 c34de90f Giorgos Verigakis
# without modification, are permitted provided that the following
5 c34de90f Giorgos Verigakis
# conditions are met:
6 c34de90f Giorgos Verigakis
#
7 c34de90f Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 c34de90f Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 c34de90f Giorgos Verigakis
#      disclaimer.
10 c34de90f Giorgos Verigakis
#
11 c34de90f Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 c34de90f Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 c34de90f Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 c34de90f Giorgos Verigakis
#      provided with the distribution.
15 c34de90f Giorgos Verigakis
#
16 c34de90f Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 c34de90f Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 c34de90f Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 c34de90f Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 c34de90f Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 c34de90f Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 c34de90f Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 c34de90f Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 c34de90f Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 c34de90f Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 c34de90f Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 c34de90f Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 c34de90f Giorgos Verigakis
#
29 c34de90f Giorgos Verigakis
# The views and conclusions contained in the software and
30 c34de90f Giorgos Verigakis
# documentation are those of the authors and should not be
31 c34de90f Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 c34de90f Giorgos Verigakis
# or implied, of GRNET S.A.
33 c34de90f Giorgos Verigakis
34 f5afd99b Giorgos Verigakis
"""
35 bfd9f988 Giorgos Verigakis
The Plankton attributes are the following:
36 0a72907b Giorgos Verigakis
  - checksum: the 'hash' meta
37 7bd1d3b5 Giorgos Verigakis
  - container_format: stored as a user meta
38 0a72907b Giorgos Verigakis
  - created_at: the 'modified' meta of the first version
39 0a72907b Giorgos Verigakis
  - deleted_at: the timestamp of the last version
40 7bd1d3b5 Giorgos Verigakis
  - disk_format: stored as a user meta
41 0a72907b Giorgos Verigakis
  - id: the 'uuid' meta
42 f5afd99b Giorgos Verigakis
  - is_public: True if there is a * entry for the read permission
43 0a72907b Giorgos Verigakis
  - location: generated based on the file's path
44 7bd1d3b5 Giorgos Verigakis
  - name: stored as a user meta
45 0a72907b Giorgos Verigakis
  - owner: the file's account
46 7bd1d3b5 Giorgos Verigakis
  - properties: stored as user meta prefixed with PROPERTY_PREFIX
47 0a72907b Giorgos Verigakis
  - size: the 'bytes' meta
48 7bd1d3b5 Giorgos Verigakis
  - status: stored as a system meta
49 7bd1d3b5 Giorgos Verigakis
  - store: is always 'pithos'
50 0a72907b Giorgos Verigakis
  - updated_at: the 'modified' meta
51 f5afd99b Giorgos Verigakis
"""
52 f5afd99b Giorgos Verigakis
53 c34de90f Giorgos Verigakis
import json
54 c23d211a Giorgos Verigakis
import warnings
55 c34de90f Giorgos Verigakis
56 c34de90f Giorgos Verigakis
from operator import itemgetter
57 c34de90f Giorgos Verigakis
from time import gmtime, strftime, time
58 c34de90f Giorgos Verigakis
59 c34de90f Giorgos Verigakis
from django.conf import settings
60 c34de90f Giorgos Verigakis
61 c34de90f Giorgos Verigakis
from pithos.backends import connect_backend
62 c34de90f Giorgos Verigakis
from pithos.backends.base import NotAllowedError
63 c34de90f Giorgos Verigakis
64 c34de90f Giorgos Verigakis
65 0a72907b Giorgos Verigakis
PLANKTON_DOMAIN = 'plankton'
66 bfd9f988 Giorgos Verigakis
PLANKTON_PREFIX = 'plankton:'
67 7bd1d3b5 Giorgos Verigakis
PROPERTY_PREFIX = 'property:'
68 7bd1d3b5 Giorgos Verigakis
69 bfd9f988 Giorgos Verigakis
PLANKTON_META = ('container_format', 'disk_format', 'name', 'properties',
70 bfd9f988 Giorgos Verigakis
                 'status')
71 c34de90f Giorgos Verigakis
72 c34de90f Giorgos Verigakis
73 7bd1d3b5 Giorgos Verigakis
def get_location(account, container, object):
74 7bd1d3b5 Giorgos Verigakis
    assert '/' not in account, "Invalid account"
75 7bd1d3b5 Giorgos Verigakis
    assert '/' not in container, "Invalid container"
76 7bd1d3b5 Giorgos Verigakis
    return 'pithos://%s/%s/%s' % (account, container, object)
77 7bd1d3b5 Giorgos Verigakis
78 7bd1d3b5 Giorgos Verigakis
def split_location(location):
79 7bd1d3b5 Giorgos Verigakis
    """Returns (accout, container, object) from a location string"""
80 7bd1d3b5 Giorgos Verigakis
    t = location.split('/', 4)
81 7bd1d3b5 Giorgos Verigakis
    assert len(t) == 5, "Invalid location"
82 7bd1d3b5 Giorgos Verigakis
    return t[2:5]
83 7bd1d3b5 Giorgos Verigakis
84 7bd1d3b5 Giorgos Verigakis
85 0a72907b Giorgos Verigakis
class BackendException(Exception):
86 0a72907b Giorgos Verigakis
    pass
87 c34de90f Giorgos Verigakis
88 c34de90f Giorgos Verigakis
89 f5afd99b Giorgos Verigakis
class ImageBackend(object):
90 f5afd99b Giorgos Verigakis
    """A wrapper arround the pithos backend to simplify image handling."""
91 c34de90f Giorgos Verigakis
    
92 c34de90f Giorgos Verigakis
    def __init__(self, user):
93 c34de90f Giorgos Verigakis
        self.user = user
94 c23d211a Giorgos Verigakis
        
95 c23d211a Giorgos Verigakis
        original_filters = warnings.filters
96 c23d211a Giorgos Verigakis
        warnings.simplefilter('ignore')         # Suppress SQLAlchemy warnings
97 bfd9f988 Giorgos Verigakis
        db_connection = settings.BACKEND_DB_CONNECTION
98 bfd9f988 Giorgos Verigakis
        block_path = settings.BACKEND_BLOCK_PATH
99 bfd9f988 Giorgos Verigakis
        self.backend = connect_backend(db_connection=db_connection,
100 bfd9f988 Giorgos Verigakis
                                       block_path=block_path)
101 c23d211a Giorgos Verigakis
        warnings.filters = original_filters     # Restore warnings
102 c34de90f Giorgos Verigakis
    
103 7bd1d3b5 Giorgos Verigakis
    def _get_image(self, location):
104 f5afd99b Giorgos Verigakis
        def format_timestamp(t):
105 f5afd99b Giorgos Verigakis
            return strftime('%Y-%m-%d %H:%M:%S', gmtime(t))
106 c34de90f Giorgos Verigakis
        
107 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
108 7bd1d3b5 Giorgos Verigakis
        
109 7bd1d3b5 Giorgos Verigakis
        try:
110 7bd1d3b5 Giorgos Verigakis
            versions = self.backend.list_versions(self.user, account,
111 7bd1d3b5 Giorgos Verigakis
                    container, object)
112 7bd1d3b5 Giorgos Verigakis
        except NameError:
113 7bd1d3b5 Giorgos Verigakis
            return None
114 7bd1d3b5 Giorgos Verigakis
        
115 7bd1d3b5 Giorgos Verigakis
        image = {}
116 7bd1d3b5 Giorgos Verigakis
        
117 7bd1d3b5 Giorgos Verigakis
        meta = self._get_meta(location)
118 7bd1d3b5 Giorgos Verigakis
        if meta:
119 7bd1d3b5 Giorgos Verigakis
            image['deleted_at'] = ''
120 7bd1d3b5 Giorgos Verigakis
        else:
121 7bd1d3b5 Giorgos Verigakis
            # Object was deleted, use the latest version
122 7bd1d3b5 Giorgos Verigakis
            version, timestamp = versions[-1]
123 7bd1d3b5 Giorgos Verigakis
            meta = self._get_meta(location, version)
124 7bd1d3b5 Giorgos Verigakis
            image['deleted_at'] = format_timestamp(timestamp)
125 7bd1d3b5 Giorgos Verigakis
        
126 0a72907b Giorgos Verigakis
        if PLANKTON_PREFIX + 'name' not in meta:
127 0a72907b Giorgos Verigakis
            return None     # Not a Plankton image
128 0a72907b Giorgos Verigakis
        
129 7bd1d3b5 Giorgos Verigakis
        permissions = self._get_permissions(location)
130 7bd1d3b5 Giorgos Verigakis
        
131 0a72907b Giorgos Verigakis
        image['checksum'] = meta['hash']
132 7bd1d3b5 Giorgos Verigakis
        image['created_at'] = format_timestamp(versions[0][1])
133 0a72907b Giorgos Verigakis
        image['id'] = meta['uuid']
134 f5afd99b Giorgos Verigakis
        image['is_public'] = '*' in permissions.get('read', [])
135 7bd1d3b5 Giorgos Verigakis
        image['location'] = location
136 7bd1d3b5 Giorgos Verigakis
        image['owner'] = account
137 0a72907b Giorgos Verigakis
        image['size'] = meta['bytes']
138 7bd1d3b5 Giorgos Verigakis
        image['store'] = 'pithos'
139 0a72907b Giorgos Verigakis
        image['updated_at'] = format_timestamp(meta['modified'])
140 7bd1d3b5 Giorgos Verigakis
        image['properties'] = {}
141 c34de90f Giorgos Verigakis
        
142 7bd1d3b5 Giorgos Verigakis
        for key, val in meta.items():
143 bfd9f988 Giorgos Verigakis
            if not key.startswith(PLANKTON_PREFIX):
144 bfd9f988 Giorgos Verigakis
                continue
145 bfd9f988 Giorgos Verigakis
            key = key[len(PLANKTON_PREFIX):]
146 bfd9f988 Giorgos Verigakis
            if key == 'properties':
147 bfd9f988 Giorgos Verigakis
                val = json.loads(val)
148 bfd9f988 Giorgos Verigakis
            if key in PLANKTON_META:
149 7bd1d3b5 Giorgos Verigakis
                image[key] = val
150 7bd1d3b5 Giorgos Verigakis
        
151 0a72907b Giorgos Verigakis
        return image
152 15137c54 Giorgos Verigakis
    
153 bfd9f988 Giorgos Verigakis
    def _get_meta(self, location, version=None):
154 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
155 7bd1d3b5 Giorgos Verigakis
        try:
156 bfd9f988 Giorgos Verigakis
            return self.backend.get_object_meta(self.user, account, container,
157 bfd9f988 Giorgos Verigakis
                    object, PLANKTON_DOMAIN, version)
158 7bd1d3b5 Giorgos Verigakis
        except NameError:
159 7bd1d3b5 Giorgos Verigakis
            return None
160 7bd1d3b5 Giorgos Verigakis
    
161 7bd1d3b5 Giorgos Verigakis
    def _get_permissions(self, location):
162 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
163 15137c54 Giorgos Verigakis
        action, path, permissions = self.backend.get_object_permissions(
164 7bd1d3b5 Giorgos Verigakis
                self.user, account, container, object)
165 f5afd99b Giorgos Verigakis
        return permissions
166 15137c54 Giorgos Verigakis
    
167 c23d211a Giorgos Verigakis
    def _store(self, f, size=None):
168 7bd1d3b5 Giorgos Verigakis
        """Breaks data into blocks and stores them in the backend"""
169 f5afd99b Giorgos Verigakis
        
170 c23d211a Giorgos Verigakis
        bytes = 0
171 f5afd99b Giorgos Verigakis
        hashmap = []
172 7bd1d3b5 Giorgos Verigakis
        backend = self.backend
173 c23d211a Giorgos Verigakis
        blocksize = backend.block_size
174 f5afd99b Giorgos Verigakis
        
175 c23d211a Giorgos Verigakis
        data = f.read(blocksize)
176 7bd1d3b5 Giorgos Verigakis
        while data:
177 c23d211a Giorgos Verigakis
            hash = backend.put_block(data)
178 f5afd99b Giorgos Verigakis
            hashmap.append(hash)
179 c23d211a Giorgos Verigakis
            bytes += len(data)
180 c23d211a Giorgos Verigakis
            data = f.read(blocksize)
181 f5afd99b Giorgos Verigakis
        
182 c23d211a Giorgos Verigakis
        if size and size != bytes:
183 c23d211a Giorgos Verigakis
            raise BackendException("Invalid size")
184 c23d211a Giorgos Verigakis
        
185 c23d211a Giorgos Verigakis
        return hashmap, bytes
186 7bd1d3b5 Giorgos Verigakis
    
187 7bd1d3b5 Giorgos Verigakis
    def _update(self, location, size, hashmap, meta, permissions):
188 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
189 7bd1d3b5 Giorgos Verigakis
        self.backend.update_object_hashmap(self.user, account, container,
190 0a72907b Giorgos Verigakis
                object, size, hashmap, PLANKTON_DOMAIN,
191 0a72907b Giorgos Verigakis
                permissions=permissions)
192 0a72907b Giorgos Verigakis
        self._update_meta(location, meta, replace=True)
193 f5afd99b Giorgos Verigakis
    
194 0a72907b Giorgos Verigakis
    def _update_meta(self, location, meta, replace=False):
195 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
196 bfd9f988 Giorgos Verigakis
        
197 bfd9f988 Giorgos Verigakis
        prefixed = {}
198 0a72907b Giorgos Verigakis
        for key, val in meta.items():
199 bfd9f988 Giorgos Verigakis
            if key == 'properties':
200 bfd9f988 Giorgos Verigakis
                val = json.dumps(val)
201 bfd9f988 Giorgos Verigakis
            if key in PLANKTON_META:
202 bfd9f988 Giorgos Verigakis
                prefixed[PLANKTON_PREFIX + key] = val
203 bfd9f988 Giorgos Verigakis
        
204 bfd9f988 Giorgos Verigakis
        self.backend.update_object_meta(self.user, account, container, object,
205 bfd9f988 Giorgos Verigakis
                PLANKTON_DOMAIN, prefixed, replace)
206 7bd1d3b5 Giorgos Verigakis
    
207 7bd1d3b5 Giorgos Verigakis
    def _update_permissions(self, location, permissions):
208 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
209 7bd1d3b5 Giorgos Verigakis
        self.backend.update_object_permissions(self.user, account, container,
210 7bd1d3b5 Giorgos Verigakis
                object, permissions)
211 f5afd99b Giorgos Verigakis
    
212 f5afd99b Giorgos Verigakis
    def add_user(self, image_id, user):
213 bfd9f988 Giorgos Verigakis
        image = self.get_image(image_id)
214 f5afd99b Giorgos Verigakis
        assert image, "Image not found"
215 f5afd99b Giorgos Verigakis
        
216 7bd1d3b5 Giorgos Verigakis
        location = image['location']
217 7bd1d3b5 Giorgos Verigakis
        permissions = self._get_permissions(location)
218 f5afd99b Giorgos Verigakis
        read = set(permissions.get('read', []))
219 f5afd99b Giorgos Verigakis
        read.add(user)
220 f5afd99b Giorgos Verigakis
        permissions['read'] = list(read)
221 7bd1d3b5 Giorgos Verigakis
        self._update_permissions(location, permissions)
222 f5afd99b Giorgos Verigakis
    
223 f5afd99b Giorgos Verigakis
    def close(self):
224 f5afd99b Giorgos Verigakis
        self.backend.close()
225 c34de90f Giorgos Verigakis
    
226 7bd1d3b5 Giorgos Verigakis
    def get_data(self, location):
227 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
228 7bd1d3b5 Giorgos Verigakis
        size, hashmap = self.backend.get_object_hashmap(self.user, account,
229 7bd1d3b5 Giorgos Verigakis
                container, object)
230 f5afd99b Giorgos Verigakis
        data = ''.join(self.backend.get_block(hash) for hash in hashmap)
231 f5afd99b Giorgos Verigakis
        assert len(data) == size
232 f5afd99b Giorgos Verigakis
        return data
233 f5afd99b Giorgos Verigakis
    
234 bfd9f988 Giorgos Verigakis
    def get_image(self, image_id):
235 0a72907b Giorgos Verigakis
        try:
236 0a72907b Giorgos Verigakis
            account, container, object = self.backend.get_uuid(self.user,
237 0a72907b Giorgos Verigakis
                    image_id)
238 0a72907b Giorgos Verigakis
        except NameError:
239 0a72907b Giorgos Verigakis
            return None
240 0a72907b Giorgos Verigakis
        
241 0a72907b Giorgos Verigakis
        location = get_location(account, container, object)
242 0a72907b Giorgos Verigakis
        return self._get_image(location)
243 f5afd99b Giorgos Verigakis
    
244 f5afd99b Giorgos Verigakis
    def iter_public(self, filters):
245 0a72907b Giorgos Verigakis
        backend = self.backend
246 0a72907b Giorgos Verigakis
        
247 bfd9f988 Giorgos Verigakis
        keys = [PLANKTON_PREFIX + 'name']
248 f5afd99b Giorgos Verigakis
        for key, val in filters.items():
249 0a72907b Giorgos Verigakis
            if key == 'size_min':
250 bfd9f988 Giorgos Verigakis
                filter = 'bytes >= %d' % int(val)
251 0a72907b Giorgos Verigakis
            elif key == 'size_max':
252 bfd9f988 Giorgos Verigakis
                filter = 'bytes <= %d' % int(val)
253 f5afd99b Giorgos Verigakis
            else:
254 0a72907b Giorgos Verigakis
                filter = '%s = %s' % (PLANKTON_PREFIX + key, val)
255 bfd9f988 Giorgos Verigakis
            keys.append(filter)
256 0a72907b Giorgos Verigakis
        
257 0a72907b Giorgos Verigakis
        for account in backend.list_accounts(None):
258 0a72907b Giorgos Verigakis
            for container in backend.list_containers(None, account,
259 0a72907b Giorgos Verigakis
                                                     shared=True):
260 0a72907b Giorgos Verigakis
                for path, version_id in backend.list_objects(None, account,
261 0a72907b Giorgos Verigakis
                        container, prefix='', delimiter='/',
262 bfd9f988 Giorgos Verigakis
                        domain=PLANKTON_DOMAIN,
263 0a72907b Giorgos Verigakis
                        keys=keys, shared=True):
264 0a72907b Giorgos Verigakis
                    location = get_location(account, container, path)
265 0a72907b Giorgos Verigakis
                    image = self._get_image(location)
266 0a72907b Giorgos Verigakis
                    if image:
267 0a72907b Giorgos Verigakis
                        yield image
268 f5afd99b Giorgos Verigakis
    
269 8482ef55 Giorgos Verigakis
    def iter_shared(self, member):
270 8482ef55 Giorgos Verigakis
        """Iterate over image ids shared to this member"""
271 8482ef55 Giorgos Verigakis
        
272 0a72907b Giorgos Verigakis
        backend = self.backend
273 8482ef55 Giorgos Verigakis
        
274 0a72907b Giorgos Verigakis
        # To get the list we connect as member and get the list shared by us
275 0a72907b Giorgos Verigakis
        for container in  backend.list_containers(member, self.user):
276 bfd9f988 Giorgos Verigakis
            for object, version_id in backend.list_objects(member, self.user,
277 bfd9f988 Giorgos Verigakis
                    container, prefix='', delimiter='/',
278 bfd9f988 Giorgos Verigakis
                    domain=PLANKTON_DOMAIN):
279 0a72907b Giorgos Verigakis
                try:
280 bfd9f988 Giorgos Verigakis
                    location = get_location(self.user, container, object)
281 bfd9f988 Giorgos Verigakis
                    meta = backend.get_object_meta(member, self.user,
282 bfd9f988 Giorgos Verigakis
                            container, object, PLANKTON_DOMAIN)
283 0a72907b Giorgos Verigakis
                    if PLANKTON_PREFIX + 'name' in meta:
284 0a72907b Giorgos Verigakis
                        yield meta['uuid']
285 0a72907b Giorgos Verigakis
                except NotAllowedError:
286 0a72907b Giorgos Verigakis
                    continue
287 f5afd99b Giorgos Verigakis
    
288 7bd1d3b5 Giorgos Verigakis
    def list_public(self, filters, params):
289 f5afd99b Giorgos Verigakis
        images = list(self.iter_public(filters))
290 7bd1d3b5 Giorgos Verigakis
        key = itemgetter(params.get('sort_key', 'created_at'))
291 7bd1d3b5 Giorgos Verigakis
        reverse = params.get('sort_dir', 'desc') == 'desc'
292 f5afd99b Giorgos Verigakis
        images.sort(key=key, reverse=reverse)
293 f5afd99b Giorgos Verigakis
        return images
294 f5afd99b Giorgos Verigakis
    
295 f5afd99b Giorgos Verigakis
    def list_users(self, image_id):
296 bfd9f988 Giorgos Verigakis
        image = self.get_image(image_id)
297 f5afd99b Giorgos Verigakis
        assert image, "Image not found"
298 c34de90f Giorgos Verigakis
        
299 7bd1d3b5 Giorgos Verigakis
        permissions = self._get_permissions(image['location'])
300 f5afd99b Giorgos Verigakis
        return [user for user in permissions.get('read', []) if user != '*']
301 c34de90f Giorgos Verigakis
    
302 c23d211a Giorgos Verigakis
    def put(self, name, f, params):
303 7bd1d3b5 Giorgos Verigakis
        assert 'checksum' not in params, "Passing a checksum is not supported"
304 7bd1d3b5 Giorgos Verigakis
        assert 'id' not in params, "Passing an ID is not supported"
305 7bd1d3b5 Giorgos Verigakis
        assert params.pop('store', 'pithos') == 'pithos', "Invalid store"
306 7bd1d3b5 Giorgos Verigakis
        assert params.setdefault('disk_format',
307 7bd1d3b5 Giorgos Verigakis
                settings.DEFAULT_DISK_FORMAT) in \
308 7bd1d3b5 Giorgos Verigakis
                settings.ALLOWED_DISK_FORMATS, "Invalid disk_format"
309 7bd1d3b5 Giorgos Verigakis
        assert params.setdefault('container_format',
310 7bd1d3b5 Giorgos Verigakis
                settings.DEFAULT_CONTAINER_FORMAT) in \
311 7bd1d3b5 Giorgos Verigakis
                settings.ALLOWED_CONTAINER_FORMATS, "Invalid container_format"
312 c34de90f Giorgos Verigakis
        
313 bfd9f988 Giorgos Verigakis
        container = settings.DEFAULT_PLANKTON_CONTAINER
314 c23d211a Giorgos Verigakis
        filename = params.pop('filename', name)
315 bfd9f988 Giorgos Verigakis
        location = 'pithos://%s/%s/%s' % (self.user, container, filename)
316 f5afd99b Giorgos Verigakis
        is_public = params.pop('is_public', False)
317 921355f8 Giorgos Verigakis
        permissions = {'read': ['*']} if is_public else {}
318 c23d211a Giorgos Verigakis
        size = params.pop('size', None)
319 c34de90f Giorgos Verigakis
        
320 c23d211a Giorgos Verigakis
        hashmap, size = self._store(f, size)
321 c34de90f Giorgos Verigakis
        
322 7bd1d3b5 Giorgos Verigakis
        meta = {}
323 7bd1d3b5 Giorgos Verigakis
        meta['properties'] = params.pop('properties', {})
324 0a72907b Giorgos Verigakis
        meta.update(name=name, status='available', **params)
325 c34de90f Giorgos Verigakis
        
326 7bd1d3b5 Giorgos Verigakis
        self._update(location, size, hashmap, meta, permissions)
327 0a72907b Giorgos Verigakis
        return self._get_image(location)
328 c34de90f Giorgos Verigakis
    
329 f5afd99b Giorgos Verigakis
    def register(self, name, location, params):
330 7bd1d3b5 Giorgos Verigakis
        assert 'id' not in params, "Passing an ID is not supported"
331 7bd1d3b5 Giorgos Verigakis
        assert location.startswith('pithos://'), "Invalid location"
332 7bd1d3b5 Giorgos Verigakis
        assert params.pop('store', 'pithos') == 'pithos', "Invalid store"
333 7bd1d3b5 Giorgos Verigakis
        assert params.setdefault('disk_format',
334 7bd1d3b5 Giorgos Verigakis
                settings.DEFAULT_DISK_FORMAT) in \
335 7bd1d3b5 Giorgos Verigakis
                settings.ALLOWED_DISK_FORMATS, "Invalid disk_format"
336 7bd1d3b5 Giorgos Verigakis
        assert params.setdefault('container_format',
337 7bd1d3b5 Giorgos Verigakis
                settings.DEFAULT_CONTAINER_FORMAT) in \
338 7bd1d3b5 Giorgos Verigakis
                settings.ALLOWED_CONTAINER_FORMATS, "Invalid container_format"
339 7bd1d3b5 Giorgos Verigakis
        
340 f5afd99b Giorgos Verigakis
        user = self.user
341 7bd1d3b5 Giorgos Verigakis
        account, container, object = split_location(location)
342 c34de90f Giorgos Verigakis
        
343 7bd1d3b5 Giorgos Verigakis
        meta = self._get_meta(location)
344 06c8fb11 Giorgos Verigakis
        assert meta, "File not found"
345 c34de90f Giorgos Verigakis
        
346 bfd9f988 Giorgos Verigakis
        size = int(params.pop('size', meta['bytes']))
347 0a72907b Giorgos Verigakis
        if size != meta['bytes']:
348 bfd9f988 Giorgos Verigakis
            print repr(size)
349 bfd9f988 Giorgos Verigakis
            print repr(meta['bytes'])
350 c34de90f Giorgos Verigakis
            raise BackendException("Invalid size")
351 c34de90f Giorgos Verigakis
        
352 0a72907b Giorgos Verigakis
        checksum = params.pop('checksum', meta['hash'])
353 0a72907b Giorgos Verigakis
        if checksum != meta['hash']:
354 c34de90f Giorgos Verigakis
            raise BackendException("Invalid checksum")
355 c34de90f Giorgos Verigakis
        
356 f5afd99b Giorgos Verigakis
        is_public = params.pop('is_public', False)
357 921355f8 Giorgos Verigakis
        permissions = {'read': ['*']} if is_public else {}
358 c34de90f Giorgos Verigakis
        
359 f5afd99b Giorgos Verigakis
        meta = {}
360 7bd1d3b5 Giorgos Verigakis
        meta['properties'] = params.pop('properties', {})
361 0a72907b Giorgos Verigakis
        meta.update(name=name, status='available', **params)
362 c34de90f Giorgos Verigakis
        
363 7bd1d3b5 Giorgos Verigakis
        self._update_meta(location, meta)
364 7bd1d3b5 Giorgos Verigakis
        self._update_permissions(location, permissions)
365 0a72907b Giorgos Verigakis
        return self._get_image(location)
366 04ba5fd4 Giorgos Verigakis
    
367 f5afd99b Giorgos Verigakis
    def remove_user(self, image_id, user):
368 bfd9f988 Giorgos Verigakis
        image = self.get_image(image_id)
369 f5afd99b Giorgos Verigakis
        assert image, "Image not found"
370 7bd1d3b5 Giorgos Verigakis
        
371 7bd1d3b5 Giorgos Verigakis
        location = image['location']
372 7bd1d3b5 Giorgos Verigakis
        permissions = self._get_permissions(location)
373 f5afd99b Giorgos Verigakis
        try:
374 f5afd99b Giorgos Verigakis
            permissions.get('read', []).remove(user)
375 f5afd99b Giorgos Verigakis
        except ValueError:
376 f5afd99b Giorgos Verigakis
            return      # User did not have access anyway
377 7bd1d3b5 Giorgos Verigakis
        self._update_permissions(location, permissions)
378 15137c54 Giorgos Verigakis
    
379 f5afd99b Giorgos Verigakis
    def replace_users(self, image_id, users):
380 bfd9f988 Giorgos Verigakis
        image = self.get_image(image_id)
381 f5afd99b Giorgos Verigakis
        assert image, "Image not found"
382 04ba5fd4 Giorgos Verigakis
        
383 7bd1d3b5 Giorgos Verigakis
        location = image['location']
384 7bd1d3b5 Giorgos Verigakis
        permissions = self._get_permissions(location)
385 f5afd99b Giorgos Verigakis
        permissions['read'] = users
386 f5afd99b Giorgos Verigakis
        if image.get('is_public', False):
387 f5afd99b Giorgos Verigakis
            permissions['read'].append('*')
388 7bd1d3b5 Giorgos Verigakis
        self._update_permissions(location, permissions)
389 7e00b33e Giorgos Verigakis
    
390 7bd1d3b5 Giorgos Verigakis
    def update(self, image_id, params):
391 bfd9f988 Giorgos Verigakis
        image = self.get_image(image_id)
392 15137c54 Giorgos Verigakis
        assert image, "Image not found"
393 7e00b33e Giorgos Verigakis
        
394 7bd1d3b5 Giorgos Verigakis
        location = image['location']
395 7bd1d3b5 Giorgos Verigakis
        is_public = params.pop('is_public', None)
396 7e00b33e Giorgos Verigakis
        if is_public is not None:
397 7bd1d3b5 Giorgos Verigakis
            permissions = self._get_permissions(location)
398 f5afd99b Giorgos Verigakis
            read = set(permissions.get('read', []))
399 7e00b33e Giorgos Verigakis
            if is_public:
400 f5afd99b Giorgos Verigakis
                read.add('*')
401 7e00b33e Giorgos Verigakis
            else:
402 f5afd99b Giorgos Verigakis
                read.discard('*')
403 f5afd99b Giorgos Verigakis
            permissions['read'] = list(read)
404 7bd1d3b5 Giorgos Verigakis
            self.backend._update_permissions(location, permissions)
405 7e00b33e Giorgos Verigakis
        
406 7bd1d3b5 Giorgos Verigakis
        meta = {}
407 7bd1d3b5 Giorgos Verigakis
        meta['properties'] = params.pop('properties', {})
408 7bd1d3b5 Giorgos Verigakis
        meta.update(**params)
409 f5afd99b Giorgos Verigakis
        
410 7bd1d3b5 Giorgos Verigakis
        self._update_meta(location, meta)
411 bfd9f988 Giorgos Verigakis
        return self.get_image(image_id)