Revision 14c94c48 snf-cyclades-app/synnefo/plankton/backend.py

b/snf-cyclades-app/synnefo/plankton/backend.py
58 58
from functools import wraps
59 59
from operator import itemgetter
60 60

  
61

  
62 61
from django.conf import settings
63 62
from pithos.backends.base import NotAllowedError, VersionNotExists
64
import snf_django.lib.astakos as lib_astakos
65 63

  
66 64
logger = logging.getLogger(__name__)
67 65

  
......
73 71
PLANKTON_META = ('container_format', 'disk_format', 'name', 'properties',
74 72
                 'status')
75 73

  
76
TRANSLATE_UUIDS = getattr(settings, 'TRANSLATE_UUIDS', False)
77

  
78

  
79
def get_displaynames(names):
80
    try:
81
        auth_url = settings.ASTAKOS_URL
82
        url = auth_url.replace('im/authenticate', 'service/api/user_catalogs')
83
        token = settings.CYCLADES_ASTAKOS_SERVICE_TOKEN
84
        uuids = lib_astakos.get_displaynames(token, names, url=url)
85
    except Exception:
86
        return {}
87

  
88
    return uuids
89

  
90

  
91
def get_location(account, container, object):
92
    assert '/' not in account, "Invalid account"
93
    assert '/' not in container, "Invalid container"
94
    return 'pithos://%s/%s/%s' % (account, container, object)
95

  
96

  
97
def split_location(location):
98
    """Returns (accout, container, object) from a location string"""
99
    t = location.split('/', 4)
100
    assert len(t) == 5, "Invalid location"
101
    return t[2:5]
102

  
103

  
104 74
from pithos.backends.util import PithosBackendPool
105 75
POOL_SIZE = 8
106 76
_pithos_backend_pool = \
......
183 153
        account, container, name = split_url(image_url)
184 154
        versions = self.backend.list_versions(self.user, account, container,
185 155
                                              name)
186

  
187 156
        if not versions:
188 157
            raise Exception("Image without versions %s" % image_url)
189

  
190
        image = {}
191

  
192 158
        try:
193 159
            meta = self._get_meta(image_url)
194
            image["deleted_at"] = ""
160
            meta["deleted"] = ""
195 161
        except NameError:
196 162
            # Object was deleted, use the latest version
197 163
            version, timestamp = versions[-1]
198 164
            meta = self._get_meta(image_url, version)
199
            image["deleted_at"] = format_timestamp(timestamp)
165
            meta["deleted"] = timestamp
166

  
167
        meta["created"] = versions[0][1]
200 168

  
201 169
        if PLANKTON_PREFIX + 'name' not in meta:
202 170
            raise ImageNotFound("'%s' is not a Plankton image" % image_url)
203 171

  
204
        image["id"] = meta["uuid"]
205
        image["location"] = image_url
206
        image["checksum"] = meta["hash"]
207
        image["created_at"] = format_timestamp(versions[0][1])
208
        image["updated_at"] = format_timestamp(meta["modified"])
209
        image["size"] = meta["bytes"]
210
        image["store"] = "pithos"
211

  
212
        if TRANSLATE_UUIDS:
213
            displaynames = get_displaynames([account])
214
            if account in displaynames:
215
                display_account = displaynames[account]
216
            else:
217
                display_account = 'unknown'
218
            image['owner'] = display_account
219
        else:
220
            image['owner'] = account
221

  
222
        # Permissions
223 172
        permissions = self._get_permissions(image_url)
224
        image["is_public"] = "*" in permissions.get('read', [])
225

  
226
        for key, val in meta.items():
227
            # Get plankton properties
228
            if key.startswith(PLANKTON_PREFIX):
229
                # Remove plankton prefix
230
                key = key.replace(PLANKTON_PREFIX, "")
231
                # Keep only those in plankton meta
232
                if key in PLANKTON_META:
233
                    if key == "properties":
234
                        val = json.loads(val)
235
                    image[key] = val
236

  
237
        return image
173
        return image_to_dict(image_url, meta, permissions)
238 174

  
239 175
    def _get_meta(self, image_url, version=None):
240 176
        """Get object's metadata."""
......
430 366
        self._update_permissions(image_url, permissions)
431 367
        return self._get_image(image_url)
432 368

  
433
    # TODO: Fix all these
434
    def _iter(self, public=False, filters=None, shared_from=None):
369
    def _list_images(self, user=None, filters=None, params=None):
435 370
        filters = filters or {}
436 371

  
437
        # Fix keys
438
        keys = [PLANKTON_PREFIX + 'name']
439
        size_range = (None, None)
440
        for key, val in filters.items():
441
            if key == 'size_min':
442
                size_range = (val, size_range[1])
443
            elif key == 'size_max':
444
                size_range = (size_range[0], val)
445
            else:
446
                keys.append('%s = %s' % (PLANKTON_PREFIX + key, val))
447

  
448
        backend = self.backend
449
        if shared_from:
450
            # To get shared images, we connect as shared_from member and
451
            # get the list shared by us
452
            user = shared_from
453
            accounts = [self.user]
454
        else:
455
            user = None if public else self.user
456
            accounts = backend.list_accounts(user)
457

  
458
        for account in accounts:
459
            for container in backend.list_containers(user, account,
460
                                                     shared=True):
461
                for path, _ in backend.list_objects(user, account, container,
462
                                                    domain=PLANKTON_DOMAIN,
463
                                                    keys=keys, shared=True,
464
                                                    size_range=size_range):
465
                    location = get_location(account, container, path)
466
                    image = self._get_image(location)
467
                    if image:
468
                        yield image
469

  
470
    @handle_backend_exceptions
471
    def iter(self, filters=None):
472
        """Iter over all images available to the user"""
473
        return self._iter(filters=filters)
474

  
475
    @handle_backend_exceptions
476
    def iter_public(self, filters=None):
477
        """Iter over public images"""
478
        return self._iter(public=True, filters=filters)
479

  
480
    @handle_backend_exceptions
481
    def iter_shared(self, filters=None, member=None):
482
        """Iter over images shared to member"""
483
        return self._iter(filters=filters, shared_from=member)
484

  
485
    @handle_backend_exceptions
486
    def list(self, filters=None, params={}):
487
        """Return all images available to the user"""
488
        images = list(self.iter(filters))
372
        # TODO: Use filters
373
        # # Fix keys
374
        # keys = [PLANKTON_PREFIX + 'name']
375
        # size_range = (None, None)
376
        # for key, val in filters.items():
377
        #     if key == 'size_min':
378
        #         size_range = (val, size_range[1])
379
        #     elif key == 'size_max':
380
        #         size_range = (size_range[0], val)
381
        #     else:
382
        #         keys.append('%s = %s' % (PLANKTON_PREFIX + key, val))
383
        _images = self.backend.get_domain_objects(domain=PLANKTON_DOMAIN,
384
                                                  user=user)
385

  
386
        images = []
387
        for (location, meta, permissions) in _images:
388
            image_url = "pithos://" + location
389
            meta["modified"] = meta["version_timestamp"]
390
            # TODO: Create metadata when registering an Image
391
            meta["created"] = meta["version_timestamp"]
392
            images.append(image_to_dict(image_url, meta, permissions))
393

  
394
        if params is None:
395
            params = {}
489 396
        key = itemgetter(params.get('sort_key', 'created_at'))
490 397
        reverse = params.get('sort_dir', 'desc') == 'desc'
491 398
        images.sort(key=key, reverse=reverse)
492 399
        return images
493 400

  
494
    @handle_backend_exceptions
495
    def list_public(self, filters, params={}):
496
        """Return public images"""
497
        images = list(self.iter_public(filters))
498
        key = itemgetter(params.get('sort_key', 'created_at'))
499
        reverse = params.get('sort_dir', 'desc') == 'desc'
500
        images.sort(key=key, reverse=reverse)
501
        return images
401
    def list_images(self, filters=None, params=None):
402
        return self._list_images(user=self.user, filters=filters,
403
                                 params=params)
404

  
405
    def list_shared_images(self, member, filters=None, params=None):
406
        images = self._list_images(user=self.user, filters=filters,
407
                                   params=params)
408
        is_shared = lambda img: not img["is_public"] and img["owner"] == member
409
        return filter(is_shared, images)
410

  
411
    def list_public_images(self, filters=None, params=None):
412
        images = self._list_images(user=None, filters=filters, params=params)
413
        return filter(lambda img: img["is_public"], images)
502 414

  
503 415

  
504 416
class ImageBackendError(Exception):
......
511 423

  
512 424
class Forbidden(ImageBackendError):
513 425
    pass
426

  
427

  
428
def image_to_dict(image_url, meta, permissions):
429
    """Render an image to a dictionary"""
430
    account, container, name = split_url(image_url)
431

  
432
    image = {}
433
    if PLANKTON_PREFIX + 'name' not in meta:
434
        raise ImageNotFound("'%s' is not a Plankton image" % image_url)
435

  
436
    image["id"] = meta["uuid"]
437
    image["location"] = image_url
438
    image["checksum"] = meta["hash"]
439
    image["created_at"] = format_timestamp(meta["created"])
440
    deleted = meta.get("deleted", None)
441
    image["deleted_at"] = format_timestamp(deleted) if deleted else ""
442
    image["updated_at"] = format_timestamp(meta["modified"])
443
    image["size"] = meta["bytes"]
444
    image["store"] = "pithos"
445
    image['owner'] = account
446

  
447
    # Permissions
448
    image["is_public"] = "*" in permissions.get('read', [])
449

  
450
    for key, val in meta.items():
451
        # Get plankton properties
452
        if key.startswith(PLANKTON_PREFIX):
453
            # Remove plankton prefix
454
            key = key.replace(PLANKTON_PREFIX, "")
455
            # Keep only those in plankton meta
456
            if key in PLANKTON_META:
457
                if key == "properties":
458
                    val = json.loads(val)
459
                image[key] = val
460

  
461
    return image

Also available in: Unified diff