Commit 46342299 authored by Georgios D. Tsoukalas's avatar Georgios D. Tsoukalas
Browse files

Merge remote branch 'origin/feature-services-endpoints' into feature-reconfigure-urls

parents 3d8ad280 bc25d966
......@@ -1003,19 +1003,20 @@ fix-superusers Transform superusers created by syncdb into Astako
cleanup-full Cleanup sessions and session catalog
commission-list List pending commissions
commission-show Show details for a pending commission
component-add Register a component
component-list List components
component-modify Modify component attributes
project-control Manage projects and applications
project-list List projects
project-show Show project details
quota List and check the integrity of user quota
reconcile-resources-astakos Reconcile resource usage of Quotaholder with Astakos DB
resource-add Add resource
resource-export-astakos Export astakos resources in json format
resource-import Register service resources
resource-import Register resources
resource-list List resources
resource-modify Modify a resource's default base quota and boolean flags
service-add Register a service
service-import Register services
service-list List services
service-modify Modify service attributes
service-show Show service details
term-add Add approval terms
user-activation-send Send user activation
......
......@@ -40,14 +40,14 @@ from snf_django.lib.db.transaction import commit_on_success_strict
from snf_django.lib import api
from snf_django.lib.api.faults import BadRequest, ItemNotFound
from astakos.im.resources import get_resources
from astakos.im.register import get_resources
from astakos.im.quotas import get_user_quotas, service_get_quotas
import astakos.quotaholder_app.exception as qh_exception
import astakos.quotaholder_app.callpoint as qh
from .util import (json_response, is_integer, are_integer,
user_from_token, service_from_token)
user_from_token, component_from_token)
@api.api_method(http_method='GET', token_required=True, user_required=False)
@user_from_token
......@@ -57,11 +57,11 @@ def quotas(request):
@api.api_method(http_method='GET', token_required=True, user_required=False)
@service_from_token
@component_from_token
def service_quotas(request):
user = request.GET.get('user')
users = [user] if user is not None else None
result = service_get_quotas(request.service_instance, users=users)
result = service_get_quotas(request.component_instance, users=users)
if user is not None and result == {}:
raise ItemNotFound("No such user '%s'" % user)
......@@ -87,10 +87,10 @@ def commissions(request):
@api.api_method(http_method='GET', token_required=True, user_required=False)
@service_from_token
@component_from_token
def get_pending_commissions(request):
data = request.GET
client_key = str(request.service_instance)
client_key = str(request.component_instance)
result = qh.get_pending_commissions(clientkey=client_key)
return json_response(result)
......@@ -115,7 +115,7 @@ def _provisions_to_list(provisions):
@csrf_exempt
@api.api_method(http_method='POST', token_required=True, user_required=False)
@service_from_token
@component_from_token
def issue_commission(request):
data = request.raw_post_data
try:
......@@ -123,7 +123,7 @@ def issue_commission(request):
except json.JSONDecodeError:
raise BadRequest("POST data should be in json format.")
client_key = str(request.service_instance)
client_key = str(request.component_instance)
provisions = input_data.get('provisions')
if provisions is None:
raise BadRequest("Provisions are missing.")
......@@ -205,7 +205,7 @@ def conflictingCF(serial):
@csrf_exempt
@api.api_method(http_method='POST', token_required=True, user_required=False)
@service_from_token
@component_from_token
@commit_on_success_strict()
def resolve_pending_commissions(request):
data = request.raw_post_data
......@@ -214,7 +214,7 @@ def resolve_pending_commissions(request):
except json.JSONDecodeError:
raise BadRequest("POST data should be in json format.")
client_key = str(request.service_instance)
client_key = str(request.component_instance)
accept = input_data.get('accept', [])
reject = input_data.get('reject', [])
......@@ -241,10 +241,10 @@ def resolve_pending_commissions(request):
@api.api_method(http_method='GET', token_required=True, user_required=False)
@service_from_token
@component_from_token
def get_commission(request, serial):
data = request.GET
client_key = str(request.service_instance)
client_key = str(request.component_instance)
try:
serial = int(serial)
except ValueError:
......@@ -261,7 +261,7 @@ def get_commission(request, serial):
@csrf_exempt
@api.api_method(http_method='POST', token_required=True, user_required=False)
@service_from_token
@component_from_token
@commit_on_success_strict()
def serial_action(request, serial):
data = request.raw_post_data
......@@ -275,7 +275,7 @@ def serial_action(request, serial):
except ValueError:
raise BadRequest("Serial should be an integer.")
client_key = str(request.service_instance)
client_key = str(request.component_instance)
accept = 'accept' in input_data
reject = 'reject' in input_data
......
......@@ -38,7 +38,7 @@ from snf_django.lib import api
from .util import (
get_uuid_displayname_catalogs as get_uuid_displayname_catalogs_util,
send_feedback as send_feedback_util,
service_from_token)
component_from_token)
import logging
logger = logging.getLogger(__name__)
......@@ -47,7 +47,7 @@ logger = logging.getLogger(__name__)
@csrf_exempt
@api.api_method(http_method='POST', token_required=True, user_required=False,
logger=logger)
@service_from_token # Authenticate service !!
@component_from_token # Authenticate service !!
def get_uuid_displayname_catalogs(request):
# Normal Response Codes: 200
# Error Response Codes: internalServerError (500)
......@@ -59,7 +59,7 @@ def get_uuid_displayname_catalogs(request):
@csrf_exempt
@api.api_method(http_method='POST', token_required=True, user_required=False,
logger=logger)
@service_from_token # Authenticate service !!
@component_from_token # Authenticate service !!
def send_feedback(request, email_template_name='im/feedback_mail.txt'):
# Normal Response Codes: 200
# Error Response Codes: internalServerError (500)
......
......@@ -39,7 +39,7 @@ from django.http import HttpResponse
from django.utils import simplejson as json
from django.template.loader import render_to_string
from astakos.im.models import AstakosUser, Service
from astakos.im.models import AstakosUser, Component
from snf_django.lib.api import faults
from snf_django.lib.api.utils import isoformat
......@@ -126,11 +126,11 @@ def user_from_token(func):
return wrapper
def service_from_token(func):
"""Decorator for authenticating service by it's token.
def component_from_token(func):
"""Decorator for authenticating component by its token.
Check that a service with the corresponding token exists. Also,
if service's token has an expiration token, check that it has not
Check that a component with the corresponding token exists. Also,
if component's token has an expiration token, check that it has not
expired.
"""
......@@ -144,18 +144,18 @@ def service_from_token(func):
if not token:
raise faults.Unauthorized("Invalid X-Auth-Token")
try:
service = Service.objects.get(auth_token=token)
except Service.DoesNotExist:
component = Component.objects.get(auth_token=token)
except Component.DoesNotExist:
raise faults.Unauthorized("Invalid X-Auth-Token")
# Check if the token has expired
expiration_date = service.auth_token_expires
expiration_date = component.auth_token_expires
if expiration_date:
expires_at = mktime(expiration_date.timetuple())
if time() > expires_at:
raise faults.Unauthorized("Authentication expired")
request.service_instance = service
request.component_instance = component
return func(request, *args, **kwargs)
return wrapper
......
......@@ -31,11 +31,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
service = "astakos"
resources = [
{"desc": "Number of pending project applications",
"name": "astakos.pending_app",
"allow_in_projects": False,
"service_type": "account",
}
]
......@@ -44,7 +44,7 @@ from django.core.management import CommandError
from synnefo.util import units
from synnefo.lib.ordereddict import OrderedDict
from astakos.im.models import AstakosUser
from astakos.im.resources import get_resources
from astakos.im.register import get_resources
DEFAULT_CONTENT_TYPE = None
......
# Copyright 2012 GRNET S.A. All rights reserved.
# Copyright 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
......@@ -32,31 +32,34 @@
# or implied, of GRNET S.A.
from django.core.management.base import BaseCommand, CommandError
from django.db.utils import IntegrityError
from astakos.im.models import Resource, Service
from astakos.im.models import Component
class Command(BaseCommand):
args = "<service> <resource> <desc> <unit>"
help = "Add a resource"
args = "<name> <component URL>"
help = "Register a component"
def handle(self, *args, **options):
if len(args) < 2:
if len(args) < 1:
raise CommandError("Invalid number of arguments")
service_name = args[0]
resource_name = args[1]
name = args[0]
url = args[1]
try:
s = Component.objects.get(name=name)
m = "There already exists a component named '%s'." % name
raise CommandError(m)
except Component.DoesNotExist:
pass
components = list(Component.objects.filter(url=url))
if components:
m = "Component URL '%s' is registered for another service." % url
raise CommandError(m)
try:
service = Service.objects.get(name=service_name)
except Service.DoesNotExist:
raise CommandError("Invalid service name")
c = Component.objects.create(name=name, url=url)
except BaseException:
raise CommandError("Failed to register component.")
else:
try:
resource = Resource(name=resource_name, service=service)
resource.save()
except IntegrityError, e:
raise CommandError(e)
# else:
# resource.meta.add(args[2:])
self.stdout.write('Token: %s\n' % c.auth_token)
# Copyright 2012, 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 astakos.im.models import Component
from synnefo.webproject.management.commands import ListCommand
class Command(ListCommand):
help = "List components"
object_class = Component
FIELDS = {
"id": ("id", "Component ID"),
"name": ("name", "Component Name"),
"url": ("url", "Component URL"),
"token": ("auth_token", "Authentication token"),
"token created": ("auth_token_created", "Token creation date"),
}
fields = ["id", "name", "url", "token"]
......@@ -35,72 +35,61 @@ from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from astakos.im.models import Service
from astakos.im.models import Component
class Command(BaseCommand):
args = "<service ID>"
help = "Modify service attributes"
args = "<component ID or name>"
help = "Modify component attributes"
option_list = BaseCommand.option_list + (
make_option('--url',
dest='url',
default=None,
help="Set service url"),
make_option('--api-url',
dest='api_url',
default=None,
help="Set service API url"),
help="Set component url"),
make_option('--auth-token',
dest='auth_token',
default=None,
help="Set a custom service auth token"),
help="Set a custom component auth token"),
make_option('--renew-token',
action='store_true',
dest='renew_token',
default=False,
help="Renew service auth token"),
make_option('--type',
dest='type',
default=None,
help="Modify service type"),
help="Renew component auth token"),
)
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Please provide a service ID")
raise CommandError("Please provide a component ID or name")
ident = args[0]
try:
service = Service.objects.get(id=int(args[0]))
except Service.DoesNotExist:
try:
ident = int(ident)
component = Component.objects.get(id=ident)
except ValueError:
component = Component.objects.get(name=ident)
except Component.DoesNotExist:
raise CommandError(
"Service does not exist. You may run snf-manage "
"service-list for available service IDs.")
"Component does not exist. You may run snf-manage "
"component-list for available component IDs.")
api_url = options.get('api_url')
url = options.get('url')
auth_token = options.get('auth_token')
renew_token = options.get('renew_token')
type = options.get('type')
if api_url:
service.api_url = api_url
if url:
service.url = url
component.url = url
if auth_token:
service.auth_token = auth_token
component.auth_token = auth_token
if renew_token and not auth_token:
service.renew_token()
if type:
service.type = type
component.renew_token()
service.save()
component.save()
if renew_token:
self.stdout.write(
'Service\'s new token: %s\n' % service.auth_token
'Component\'s new token: %s\n' % component.auth_token
)
......@@ -34,15 +34,12 @@
from django.utils import simplejson as json
from django.core.management.base import BaseCommand
from astakos.im.astakos_resources import service, resources
from astakos.im.astakos_resources import resources
class Command(BaseCommand):
help = "Export astakos resources in json format"
def handle(self, *args, **options):
data = {'service': service,
'resources': resources,
}
output = json.dumps(data, indent=4)
output = json.dumps(resources, indent=4)
self.stdout.write(output + '\n')
......@@ -38,12 +38,12 @@ from django.db.utils import IntegrityError
from django.utils import simplejson as json
from snf_django.lib.db.transaction import commit_on_success_strict
from astakos.im.resources import add_resource
from astakos.im.register import add_resource, ResourceException
from astakos.im.models import Service
class Command(BaseCommand):
help = "Register service resources"
help = "Register resources"
option_list = BaseCommand.option_list + (
make_option('--json',
......@@ -61,40 +61,33 @@ class Command(BaseCommand):
else:
with open(json_file) as file_data:
m = ('Input should be a JSON dict containing "service" '
'and "resource" keys.')
m = 'Input should be a JSON list.'
try:
data = json.load(file_data)
except json.JSONDecodeError:
raise CommandError(m)
if not isinstance(data, dict):
if not isinstance(data, list):
raise CommandError(m)
else:
try:
service = data['service']
resources = data['resources']
except KeyError:
raise CommandError(m)
self.add_resources(service, resources)
self.add_resources(data)
@commit_on_success_strict()
def add_resources(self, service, resources):
try:
s = Service.objects.get(name=service)
except Service.DoesNotExist:
raise CommandError("Service '%s' is not registered." % (service))
def add_resources(self, resources):
output = []
for resource in resources:
if not isinstance(resource, dict):
raise CommandError("Malformed resource dict.")
r, exists = add_resource(s, resource)
try:
r, exists = add_resource(resource)
except ResourceException as e:
raise CommandError(e.message)
name = r.name
if exists:
m = "Resource '%s' updated in database.\n" % (name)
else:
m = ("Resource '%s' created in database with default "
"quota limit 0.\n" % (name))
self.stdout.write(m)
output.append(m)
for line in output:
self.stdout.write(line)
......@@ -51,14 +51,14 @@ class Command(ListCommand):
FIELDS = {
"id": ("id", "ID"),
"name": ("name", "Resource Name"),
"service": ("service", "Service"),
"service type": ("service_type", "Service"),
"limit": ("limit_with_unit", "Base Quota"),
"description": ("desc", "Description"),
"allow_in_projects": ("allow_in_projects",
"Make resource available in projects"),
}
fields = ["id", "name", "service", "limit", "allow_in_projects",
fields = ["id", "name", "service type", "limit", "allow_in_projects",
"description"]
def show_limit(self, resource):
......
......@@ -37,7 +37,7 @@ from django.utils import simplejson as json
from synnefo.webproject.management import utils
from astakos.im.models import Resource
from astakos.im.resources import update_resource
from astakos.im.register import update_resource
from ._common import show_resource_value, style_options, check_style, units
......
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
# Copyright 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
......@@ -32,73 +32,70 @@
# or implied, of GRNET S.A.
from optparse import make_option
import string
from django.core.management.base import BaseCommand, CommandError
from django.db.utils import IntegrityError
from django.utils import simplejson as json
from astakos.im.models import Service
from snf_django.lib.db.transaction import commit_on_success_strict
from astakos.im.register import add_service, ServiceException
from astakos.im.models import Component
class Command(BaseCommand):
args = "<name> <service URL> <API URL> "
help = "Register a service"
help = "Register services"
option_list = BaseCommand.option_list + (
make_option('--type',
dest='type',
help="Service type"),
make_option('-f', '--no-confirm',
action='store_true',
default=False,
dest='force',
help="Do not ask for confirmation"),
make_option('--json',
dest='json',
metavar='<json.file>',
help="Load service definitions from a json file"),
)
@commit_on_success_strict()
def handle(self, *args, **options):