Commit dcb93ddf authored by Olga Brani's avatar Olga Brani
Browse files

Merged demo

parent 6a0dc5a3
......@@ -6,3 +6,5 @@ docs/build
.project
.pydevproject
snf-astakos-app/astakos/version.py
snf-astakos-app/distribute-0.6.10-py2.6.egg
snf-astakos-app/distribute-0.6.10.tar.gz
\ No newline at end of file
......@@ -85,18 +85,45 @@ ASTAKOS_INVITATION_EMAIL_SUBJECT 'Invitation to %s alpha2 testing' %
ASTAKOS_GREETING_EMAIL_SUBJECT 'Welcome to %s alpha2 testing' % SITENAME Welcome email subject
ASTAKOS_FEEDBACK_EMAIL_SUBJECT 'Feedback from %s alpha2 testing' % SITENAME Feedback email subject
ASTAKOS_VERIFICATION_EMAIL_SUBJECT '%s alpha2 testing account activation is needed' % SITENAME Account activation email subject
ASTAKOS_ADMIN_NOTIFICATION_EMAIL_SUBJECT '%s alpha2 testing account created (%%(user)s)' % SITENAME Account creation admin notification email subject
ASTAKOS_ACCOUNT_CREATION_SUBJECT '%s alpha2 testing account created (%%(user)s)' % SITENAME Account creation email subject
ASTAKOS_GROUP_CREATION_SUBJECT '%s alpha2 testing group created (%%(group)s)' % SITENAME Group creation email subject
ASTAKOS_HELPDESK_NOTIFICATION_EMAIL_SUBJECT '%s alpha2 testing account activated (%%(user)s)' % SITENAME Account activation helpdesk notification email subject
ASTAKOS_EMAIL_CHANGE_EMAIL_SUBJECT 'Email change on %s alpha2 testing' % SITENAME Email change subject
ASTAKOS_PASSWORD_RESET_EMAIL_SUBJECT 'Password reset on %s alpha2 testing' % SITENAME Password change email subject
ASTAKOS_QUOTA_HOLDER_URL '' The quota holder URI
e.g. ``http://localhost:8080/api/quotaholder/v``
ASTAKOS_SERVICES {'cyclades': {'url':'https://node1.example.com/ui/', 'quota': {'vm': 2}}, Cloud service default url and quota
'pithos+': {'url':'https://node2.example.com/ui/', 'quota': {
'diskspace': 50 * 1024 * 1024 * 1024}}})
e.g. ``http://localhost:8080/api/quotaholder/v``
ASTAKOS_SERVICES {'cyclades': {'resources': [{'desc': 'Number of virtual machines', Default cloud service information
'group': 'storage',
'name': 'vm',
'uplimit': 2},
{'desc': 'Virtual machine disk size',
'group': 'storage',
'name': 'disksize',
'unit': 'GB',
'uplimit': 5},
{'desc': 'Number of virtual machine processors',
'group': 'storage',
'name': 'cpu',
'uplimit': 1},
{'desc': 'Virtual machines',
'group': 'storage',
'name': 'ram',
'unit': 'MB',
'uplimit': 1024}],
'url': 'https://node1.example.com/ui/'},
'pithos+': {'resources': [{'desc': 'Pithos account diskspace',
'group': 'compute',
'name': 'diskspace',
'unit': 'bytes',
'uplimit': 5368709120}],
'url': 'https://node2.example.com/ui/'}}
ASTAKOS_AQUARIUM_URL '' The billing (aquarium) URI
e.g. ``http://localhost:8888/user``
e.g. ``http://localhost:8888/user``
ASTAKOS_PAGINATE_BY 10 Number of object to be displayed per page
ASTAKOS_NEWPASSWD_INVALIDATE_TOKEN True Enforce token renewal on password change/reset. If set to False, user can optionally decide
whether to renew the token or not.
=========================================== ============================================================================= ===========================================================================================
Administrator functions
......
......@@ -38,8 +38,9 @@ from django.utils.translation import ugettext as _
from astakos.im.models import AstakosUser
from astakos.im.forms import LocalUserCreationForm, ShibbolethUserCreationForm
from astakos.im.util import get_invitation
from astakos.im.functions import send_verification, send_activation, \
send_admin_notification, activate
from astakos.im.functions import (send_verification, send_activation,
send_account_creation_notification,
send_group_creation_notification, activate)
from astakos.im.settings import INVITATIONS_ENABLED, MODERATION_ENABLED, SITENAME, RE_USER_EMAIL_PATTERNS
import logging
......@@ -129,10 +130,9 @@ class ActivationBackend(object):
send_activation(user, activation_template_name)
return VerificationSent()
else:
send_admin_notification(
send_account_creation_notification(
template_name=admin_email_template_name,
dictionary={'user': user, 'group_creation': True},
subject='%s alpha2 testing account notification' % SITENAME
dictionary={'user': user, 'group_creation': True}
)
return NotificationSent()
except BaseException, e:
......
......@@ -173,33 +173,33 @@ def get_menu(request, with_extra_links=False, with_signout=True):
item = MenuItem
item.current_path = absolute(request, request.path)
append(item(
url=absolute(request, reverse('index')),
name=user.email))
url=absolute(request, reverse('index')),
name=user.email))
append(item(url=absolute(request, reverse('edit_profile')),
name="My account"))
if with_extra_links:
if user.has_usable_password() and user.provider in ('local', ''):
append(item(
url=absolute(request, reverse('password_change')),
name="Change password"))
url=absolute(request, reverse('password_change')),
name="Change password"))
if EMAILCHANGE_ENABLED:
append(item(
url=absolute(request, reverse('email_change')),
name="Change email"))
url=absolute(request, reverse('email_change')),
name="Change email"))
if INVITATIONS_ENABLED:
append(item(
url=absolute(request, reverse('invite')),
name="Invitations"))
url=absolute(request, reverse('invite')),
name="Invitations"))
append(item(
url=absolute(request, reverse('feedback')),
name="Feedback"))
url=absolute(request, reverse('feedback')),
name="Feedback"))
append(item(
url=absolute(request, reverse('group_list')),
name="Groups",
submenu=(item(
url=absolute(request,
reverse('group_list')),
name="Overview"),
url=absolute(request, reverse('group_list')),
name="Groups",
submenu=(item(
url=absolute(request,
reverse('group_list')),
name="Overview"),
item(
url=absolute(request,
reverse('group_create_list')),
......@@ -209,18 +209,18 @@ def get_menu(request, with_extra_links=False, with_signout=True):
reverse('group_search')),
name="Join"),)))
append(item(
url=absolute(request, reverse('resource_list')),
name="Resources"))
url=absolute(request, reverse('resource_list')),
name="Resources"))
append(item(
url=absolute(request, reverse('billing')),
name="Billing"))
url=absolute(request, reverse('billing')),
name="Billing"))
append(item(
url=absolute(request, reverse('timeline')),
name="Timeline"))
url=absolute(request, reverse('timeline')),
name="Timeline"))
if with_signout:
append(item(
url=absolute(request, reverse('logout')),
name="Sign out"))
url=absolute(request, reverse('logout')),
name="Sign out"))
callback = request.GET.get('callback', None)
data = json.dumps(tuple(l))
......
# Copyright 2011-2012 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 astakos.im.api.backends.lib.django import DjangoBackend
def get_backend():
return DjangoBackend()
class ItemNotExists(NameError):
pass
class ItemExists(NameError):
pass
class MissingIdentifier(IOError):
pass
class BaseBackend(object):
def update_user():
pass
def create_user():
pass
# Copyright 2011-2012 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 django.db import IntegrityError, transaction
from django.core.exceptions import ObjectDoesNotExist
from functools import wraps
from smtplib import SMTPException
from astakos.im.models import AstakosUser, Resource, Service, RESOURCE_SEPARATOR
from astakos.im.api.backends.base import (BaseBackend, ItemNotExists,
ItemExists, MissingIdentifier)
from astakos.im.util import reserved_email, model_to_dict
from astakos.im.endpoints.quotaholder import get_quota
import logging
logger = logging.getLogger(__name__)
DEFAULT_CONTENT_TYPE = None
def safe(propagate_exceptions=False):
"""Decorator function for views that implement an API method."""
def decorator(func):
@transaction.commit_manually
@wraps(func)
def wrapper(self, *args, **kwargs):
logger.debug('%s %s %s' % (func, args, kwargs))
try:
r = func(self, *args, **kwargs) or ()
except Exception, e:
logger.exception(e)
transaction.rollback()
if propagate_exceptions:
raise e
else:
args = list(args)
args.append(e)
r = args
else:
transaction.commit()
r = filter(bool, r) # filter out None elements
return list(r)
return wrapper
return decorator
class DjangoBackend(BaseBackend):
def _lookup_object(self, model, **kwargs):
"""
Returns an object of the specific model having this id.
"""
if not kwargs:
raise MissingIdentifier
try:
return model.objects.get(**kwargs)
except model.DoesNotExist:
raise ItemNotExists()
def _lookup_user(self, id):
"""
Returns an AstakosUser having this id.
"""
return self._lookup_object(AstakosUser, id=id)
def _lookup_service(self, id):
"""
Returns an Service having this id.
"""
return self._lookup_object(Service, id=id)
def _list(self, model, filter=()):
q = model.objects.all()
if filter:
q = q.filter(id__in=filter)
return map(lambda o: model_to_dict(o, exclude=[]), q)
def _create_object(self, model, **kwargs):
o = model(**kwargs)
o.save()
return o
def _update_object(self, model, id, save=True, **kwargs):
o = self._lookup_object(model, id=id)
if kwargs:
o.__dict__.update(kwargs)
if save:
o.save()
return o
@safe()
def update_user(self, user_id, renew_token=False, **kwargs):
user = self._update_object(AstakosUser, user_id, save=False, **kwargs)
if renew_token:
user.renew_token()
if kwargs or renew_token:
user.save()
@safe()
def create_user(self, **kwargs):
policies = kwargs.pop('policies', ())
permissions = kwargs.pop('permissions', ())
groups = kwargs.pop('groups', ())
password = kwargs.pop('password', None)
u = self._create_object(AstakosUser, **kwargs)
if password:
u.set_password(password)
u.permissions = permissions
u.policies = policies
u.extended_groups = groups
@safe()
def add_policies(self, user_id, update=False, policies=()):
user = self._lookup_user(user_id)
rejected = []
append = rejected.append
for p in policies:
service = p.get('service')
resource = p.get('resource')
uplimit = p.get('uplimit')
try:
user.add_policy(service, resource, uplimit, update)
except (ObjectDoesNotExist, IntegrityError), e:
append((service, resource, e))
if rejected:
raise Exception(rejected)
@safe()
def remove_policies(self, user_id, policies=()):
user = self._lookup_user(user_id)
if not user:
return user_id
rejected = []
append = rejected.append
for p in policies:
service = p.get('service')
resource = p.get('resource')
try:
user.delete_policy(service, resource)
except ObjectDoesNotExist, e:
append((service, resource, e))
if rejected:
raise Exception(rejected)
@safe()
def add_permissions(self, user_id, permissions=()):
user = self._lookup_user(user_id)
rejected = []
append = rejected.append
for p in permissions:
try:
user.add_permission(p)
except IntegrityError, e:
append((p, e))
if rejected:
raise Exception(rejected)
@safe()
def remove_permissions(self, user_id, permissions=()):
user = self._lookup_user(user_id)
rejected = []
append = rejected.append
for p in permissions:
try:
user.remove_permission(p)
except (ObjectDoesNotExist, IntegrityError), e:
append((p, e))
if rejected:
raise Exception(rejected)
@safe()
def invite_users(self, senderid, recipients=()):
user = self._lookup_user(senderid)
rejected = []
append = rejected.append
for r in recipients:
try:
user.invite(r.get('email'), r.get('realname'))
except (IntegrityError, SMTPException), e:
append((email, e))
if rejected:
raise Exception(rejected)
@safe(propagate_exceptions=True)
def list_users(self, filter=()):
return self._list(AstakosUser, filter=filter)
@safe(propagate_exceptions=True)
def get_resource_usage(self, user_id):
user = self._lookup_user(user_id)
c, data = get_quota((user,))
resources = []
append = resources.append
for t in data:
t = (i if i else 0 for i in t)
(entity, name, quantity, capacity, importLimit, exportLimit,
imported, exported, returned, released, flags) = t
service, sep, resource = name.partition(RESOURCE_SEPARATOR)
resource = Resource.objects.select_related().get(
service__name=service, name=resource)
d = dict(name=name,
description=resource.desc,
unit=resource.unit or '',
maxValue=quantity + capacity,
currValue=quantity + imported - released - exported + returned)
append(d)
return resources
@safe(propagate_exceptions=True)
def list_resources(self, filter=()):
return self._list(Resource, filter=filter)
@safe()
def create_service(self, **kwargs):
resources = kwargs.pop('resources', ())
s = self._create_object(Service, **kwargs)
s.resources = resources
@safe()
def remove_services(self, ids=()):
# TODO return information for unknown ids
q = Service.objects.filter(id__in=ids)
q.delete()
@safe()
def update_service(self, service_id, renew_token=False, **kwargs):
s = self._update_object(Service, service_id, save=False, **kwargs)
if renew_token:
s.renew_token()
if kwargs or renew_token:
s.save()
@safe()
def add_resources(self, service_id, update=False, resources=()):
s = self._lookup_service(service_id)
rejected = []
append = rejected.append
for r in resources:
try:
rr = r.copy()
resource_id = rr.pop('id', None)
if update:
if not resource_id:
raise MissingIdentifier
resource = self._update_object(Resource, resource_id, **rr)
else:
resource = self._create_object(Resource, service=s, **rr)
except Exception, e:
append((r, e))
if rejected:
raise Exception(rejected)
@safe()
def remove_resources(self, service_id, ids=()):
# TODO return information for unknown ids
q = Resource.objects.filter(service__id=service_id,
id__in=ids)
q.delete()
@safe()
def create_group(self, **kwargs):
policies = kwargs.pop('policies', ())
permissions = kwargs.pop('permissions', ())
members = kwargs.pop('members', ())
owners = kwargs.pop('owners', ())
g = self._create_object(AstakosGroup, **kwargs)
g.permissions = permissions
g.policies = policies
g.members = members
g.owners = owners
\ No newline at end of file
# Copyright 2011-2012 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 astakos.im.api.spec import AstakosAPI
from backends import get_backend
from commissioning import (Callpoint,
# CommissionException,
# CorruptedError, InvalidDataError,
# InvalidKeyError, NoEntityError,
# NoQuantityError, NoCapacityError,
# ExportLimitError, ImportLimitError
)
# from commissioning.utils.newname import newname
# from django.db.models import Model, BigIntegerField, CharField, ForeignKey, Q
# from django.db import transaction, IntegrityError
# from .models import (Holder, Entity, Policy, Holding,
# Commission, Provision, ProvisionLog, now)
class AstakosDjangoDBCallpoint():
api_spec = AstakosAPI()
# http_exc_lookup = {
# CorruptedError: 550,