Commit 4fbcfca8 authored by Christos Stavrakakis's avatar Christos Stavrakakis

cyclades: Major refactor to plankton backend

* Rename ImageBackend to PlanktonBackend
* Rewrite PlanktonBackend methods in order that they refer to Pithos
  objects by their UUID
* Convert PlanktonBackend to context manager that is responsible for
  returning the PithosBackend connection back to the pool, and remove
  stale 'image_backend' context manager
* Make PlanktonBackend raise cloud (API) faults
parent 4c2c501f
......@@ -43,7 +43,7 @@ from django.db.models import Count, Sum
from snf_django.lib.astakos import UserCache
from synnefo.db.models import VirtualMachine, Network, Backend
from synnefo.plankton.utils import image_backend
from synnefo.plankton.backend import PlanktonBackend
from synnefo.logic import backend as backend_mod
......@@ -204,7 +204,7 @@ class ImageCache(object):
def get_image(self, imageid, userid):
if not imageid in self.images:
try:
with image_backend(userid) as ib:
with PlanktonBackend(userid) as ib:
image = ib.get_image(imageid)
properties = image.get("properties")
os = properties.get("os",
......
......@@ -44,7 +44,7 @@ from django.utils import simplejson as json
from snf_django.lib import api
from snf_django.lib.api import faults, utils
from synnefo.api import util
from synnefo.plankton.utils import image_backend
from synnefo.plankton import backend
log = getLogger(__name__)
......@@ -131,8 +131,8 @@ def list_images(request, detail=False):
log.debug('list_images detail=%s', detail)
since = utils.isoparse(request.GET.get('changes-since'))
with image_backend(request.user_uniq) as backend:
images = backend.list_images()
with backend.PlanktonBackend(request.user_uniq) as b:
images = b.list_images()
if since:
updated_since = lambda img: date_parse(img["updated_at"]) >= since
images = ifilter(updated_since, images)
......@@ -180,8 +180,8 @@ def get_image_details(request, image_id):
# overLimit (413)
log.debug('get_image_details %s', image_id)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
with backend.PlanktonBackend(request.user_uniq) as b:
image = b.get_image(image_id)
reply = image_to_dict(image)
if request.serialization == 'xml':
......@@ -202,8 +202,8 @@ def delete_image(request, image_id):
# overLimit (413)
log.info('delete_image %s', image_id)
with image_backend(request.user_uniq) as backend:
backend.unregister(image_id)
with backend.PlanktonBackend(request.user_uniq) as b:
b.unregister(image_id)
log.info('User %s deleted image %s', request.user_uniq, image_id)
return HttpResponse(status=204)
......@@ -218,8 +218,8 @@ def list_metadata(request, image_id):
# overLimit (413)
log.debug('list_image_metadata %s', image_id)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
with backend.PlanktonBackend(request.user_uniq) as b:
image = b.get_image(image_id)
metadata = image['properties']
return util.render_metadata(request, metadata, use_values=False,
status=200)
......@@ -238,8 +238,8 @@ def update_metadata(request, image_id):
req = utils.get_request_dict(request)
log.info('update_image_metadata %s %s', image_id, req)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
with backend.PlanktonBackend(request.user_uniq) as b:
image = b.get_image(image_id)
try:
metadata = req['metadata']
assert isinstance(metadata, dict)
......@@ -249,7 +249,7 @@ def update_metadata(request, image_id):
properties = image['properties']
properties.update(metadata)
backend.update_metadata(image_id, dict(properties=properties))
b.update_metadata(image_id, dict(properties=properties))
return util.render_metadata(request, properties, status=201)
......@@ -265,8 +265,8 @@ def get_metadata_item(request, image_id, key):
# overLimit (413)
log.debug('get_image_metadata_item %s %s', image_id, key)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
with backend.PlanktonBackend(request.user_uniq) as b:
image = b.get_image(image_id)
val = image['properties'].get(key)
if val is None:
raise faults.ItemNotFound('Metadata key not found.')
......@@ -296,12 +296,12 @@ def create_metadata_item(request, image_id, key):
raise faults.BadRequest('Malformed request.')
val = metadict[key]
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
with backend.PlanktonBackend(request.user_uniq) as b:
image = b.get_image(image_id)
properties = image['properties']
properties[key] = val
backend.update_metadata(image_id, dict(properties=properties))
b.update_metadata(image_id, dict(properties=properties))
return util.render_meta(request, {key: val}, status=201)
......@@ -319,11 +319,11 @@ def delete_metadata_item(request, image_id, key):
# overLimit (413),
log.info('delete_image_metadata_item %s %s', image_id, key)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
with backend.PlanktonBackend(request.user_uniq) as b:
image = b.get_image(image_id)
properties = image['properties']
properties.pop(key, None)
backend.update_metadata(image_id, dict(properties=properties))
b.update_metadata(image_id, dict(properties=properties))
return HttpResponse(status=204)
......@@ -51,7 +51,7 @@ from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
Network, NetworkInterface, SecurityGroup,
BridgePoolTable, MacPrefixPoolTable, IPAddress,
IPPoolTable)
from synnefo.plankton.utils import image_backend
from synnefo.plankton.backend import PlanktonBackend
from synnefo.cyclades_settings import cyclades_services, BASE_HOST
from synnefo.lib.services import get_service_path
......@@ -163,7 +163,7 @@ def get_vm_meta(vm, key):
def get_image(image_id, user_id):
"""Return an Image instance or raise ItemNotFound."""
with image_backend(user_id) as backend:
with PlanktonBackend(user_id) as backend:
return backend.get_image(image_id)
......
......@@ -32,7 +32,7 @@ from django.core.management.base import BaseCommand
from optparse import make_option
from snf_django.management.utils import pprint_table
from synnefo.plankton.utils import image_backend
from synnefo.plankton.backend import PlanktonBackend
class Command(BaseCommand):
......@@ -50,7 +50,7 @@ class Command(BaseCommand):
def handle(self, **options):
user = options['userid']
with image_backend(user) as backend:
with PlanktonBackend(user) as backend:
images = backend._list_images(user)
images.sort(key=lambda x: x['created_at'], reverse=True)
......
# Copyright 2012 GRNET S.A. All rights reserved.
# Copyright 2012-2014 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
......@@ -30,7 +30,7 @@
from django.core.management.base import BaseCommand, CommandError
from synnefo.plankton.utils import image_backend
from synnefo.plankton.backend import PlanktonBackend
from snf_django.management import utils
......@@ -44,11 +44,7 @@ class Command(BaseCommand):
raise CommandError("Please provide an image ID")
image_id = args[0]
with image_backend(None) as backend:
images = backend._list_images(None)
try:
image = filter(lambda x: x["id"] == image_id, images)[0]
except IndexError:
raise CommandError("Image not found. Use snf-manage image-list"
" to get the list of all images.")
utils.pprint_table(out=self.stdout, table=[image.values()], headers=image.keys(), vertical=True)
with PlanktonBackend(None) as backend:
image = backend.get_image(image_id)
utils.pprint_table(out=self.stdout, table=[image.values()],
headers=image.keys(), vertical=True)
This diff is collapsed.
# Copyright 2011-2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from contextlib import contextmanager
from synnefo.plankton import backend
from snf_django.lib.api import faults
@contextmanager
def image_backend(user_id):
"""Context manager for ImageBackend.
Context manager for using ImageBackend in API methods. Handles
opening and closing a connection to Pithos and converting backend
erros to cloud faults.
"""
image_backend = backend.get_backend()(user_id)
try:
yield image_backend
except backend.Forbidden as e:
raise faults.Forbidden
except backend.ImageNotFound:
raise faults.ItemNotFound
except backend.InvalidMetadata as e:
raise faults.BadRequest(str(e))
finally:
image_backend.close()
......@@ -43,8 +43,8 @@ from django.http import HttpResponse
from snf_django.lib import api
from snf_django.lib.api import faults
from synnefo.util.text import uenc
from synnefo.plankton.utils import image_backend
from synnefo.plankton.backend import split_url, InvalidLocation
from synnefo.plankton.backend import PlanktonBackend
from synnefo.plankton.backend import split_url
FILTERS = ('name', 'container_format', 'disk_format', 'status', 'size_min',
......@@ -109,10 +109,10 @@ def _get_image_headers(request):
for key, val in request.META.items():
if key.startswith(META_PROPERTY_PREFIX):
name = normalize(key[META_PROPERTY_PREFIX_LEN:])
headers['properties'][unquote(name)] = unquote(val)
headers['properties'][unquote(name)] = unquote(uenc(val))
elif key.startswith(META_PREFIX):
name = normalize(key[META_PREFIX_LEN:])
headers[unquote(name)] = unquote(val)
headers[unquote(name)] = unquote(uenc(val))
is_public = headers.get('is_public', None)
if is_public is not None:
......@@ -149,7 +149,7 @@ def add_image(request):
if not set(params.keys()).issubset(set(ADD_FIELDS)):
raise faults.BadRequest("Invalid parameters")
name = params.pop('name')
name = params.pop('name', None)
if name is None:
raise faults.BadRequest("Image 'name' parameter is required")
elif len(uenc(name)) == 0:
......@@ -160,13 +160,13 @@ def add_image(request):
try:
split_url(location)
except InvalidLocation:
except AssertionError:
raise faults.BadRequest("Invalid location '%s'" % location)
validate_fields(params)
if location:
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
image = backend.register(name, location, params)
else:
#f = StringIO(request.body)
......@@ -193,7 +193,7 @@ def delete_image(request, image_id):
"""
log.info("delete_image '%s'" % image_id)
userid = request.user_uniq
with image_backend(userid) as backend:
with PlanktonBackend(userid) as backend:
backend.unregister(image_id)
log.info("User '%s' deleted image '%s'" % (userid, image_id))
return HttpResponse(status=204)
......@@ -211,7 +211,7 @@ def add_image_member(request, image_id, member):
"""
log.debug('add_image_member %s %s', image_id, member)
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
backend.add_user(image_id, member)
return HttpResponse(status=204)
......@@ -250,7 +250,7 @@ def get_image_meta(request, image_id):
3.4. Requesting Detailed Metadata on a Specific Image
"""
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
image = backend.get_image(image_id)
return _create_image_response(image)
......@@ -263,7 +263,7 @@ def list_image_members(request, image_id):
3.7. Requesting Image Memberships
"""
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
users = backend.list_users(image_id)
members = [{'member_id': u, 'can_share': False} for u in users]
......@@ -313,7 +313,7 @@ def list_images(request, detail=False):
except ValueError:
raise faults.BadRequest("Malformed request.")
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
images = backend.list_images(filters, params)
# Remove keys that should not be returned
......@@ -342,10 +342,9 @@ def list_shared_images(request, member):
log.debug('list_shared_images %s', member)
images = []
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
for image in backend.list_shared_images(member=member):
image_id = image['id']
images.append({'image_id': image_id, 'can_share': False})
images.append({'image_id': image["id"], 'can_share': False})
data = json.dumps({'shared_images': images}, indent=settings.DEBUG)
return HttpResponse(data)
......@@ -360,7 +359,7 @@ def remove_image_member(request, image_id, member):
"""
log.debug('remove_image_member %s %s', image_id, member)
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
backend.remove_user(image_id, member)
return HttpResponse(status=204)
......@@ -386,7 +385,7 @@ def update_image(request, image_id):
validate_fields(meta)
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
image = backend.update_metadata(image_id, meta)
return _create_image_response(image)
......@@ -411,7 +410,7 @@ def update_image_members(request, image_id):
except (ValueError, KeyError, TypeError):
return HttpResponse(status=400)
with image_backend(request.user_uniq) as backend:
with PlanktonBackend(request.user_uniq) as backend:
backend.replace_users(image_id, members)
return HttpResponse(status=204)
......
......@@ -221,6 +221,12 @@ class BaseAPITest(TestCase):
response = self.client.get(url, *args, **kwargs)
return response
def head(self, url, user='user', *args, **kwargs):
with astakos_user(user):
with mocked_quotaholder():
response = self.client.head(url, *args, **kwargs)
return response
def delete(self, url, user='user'):
with astakos_user(user):
with mocked_quotaholder() as m:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment