Revision a24b5bda

b/docs/astakos-api-guide.rst
20 20
=========================  ================================
21 21
Revision                   Description
22 22
=========================  ================================
23
0.14 (June 03, 2013)       Remove endpoint listing
23 24
0.14 (May 28, 2013)        Extend token api with authenticate call
24 25
0.14 (May 23, 2013)        Extend api to list endpoints
25 26
0.14 (May 14, 2013)        Do not serve user quotas in :ref:`authenticate-api-label`
......
474 475
401 (Unauthorized)          Invalid token or invalid creadentials or tenantName does not comply with the provided token
475 476
500 (Internal Server Error) The request cannot be completed because of an internal error
476 477
=========================== =====================
477

  
478

  
479

  
480
Get endpoints
481
^^^^^^^^^^^^^
482

  
483
Return a json (or xml) formatted dictionary containing information about registered endpoints
484

  
485
========================================= =========  ==================
486
Uri                                       Method     Description
487
========================================= =========  ==================
488
``/astakos/api/tokens/<token>/endpoints`` GET        Returns a list registered endpoints
489
========================================= =========  ==================
490

  
491
|
492

  
493
====================  ============================
494
Request Header Name   Value
495
====================  ============================
496
X-Auth-Token          User authentication token
497
====================  ============================
498

  
499
|
500

  
501
======================  ============================
502
Request Parameter Name  Value
503

  
504
======================  ============================
505
belongsTo               Check that the token belongs to a supplied user
506
marker                  Return endpoints (ordered by ID) whose ID is higher than the marker
507
limit                   Maximum number of endpoints to return
508
======================  ============================
509

  
510
|
511

  
512
Example json reply:
513

  
514
::
515

  
516
    {"endpoints": [
517
        {"name": "cyclades",
518
         "region": "cyclades",
519
         "internalURL": "https://node1.example.com/v1",
520
         "adminURL": "https://node1.example.com/v1",
521
         "type": null,
522
         "id": 5,
523
         "publicURL": "https://node1.example.com/vi/"},
524
        {"name": "pithos",
525
         "region": "pithos",
526
         "internalURL": "https://node2.example.com/vi/",
527
         "adminURL": "https://node2.example.com/v1",
528
         "type": null,
529
         "id": 6,
530
         "publicURL": "https://node2.example.com/vi/"},
531
    ],
532
    "endpoint_links": [{
533
        "href": "/astakos/api/tokens/0000/endpoints?marker=6&limit=10000",
534
         "rel": "next"}]}
535

  
536

  
537
Example xml reply:
538

  
539
::
540

  
541
    <?xml version="1.0" encoding="UTF-8"?>
542
    <endpoints xmlns="http://docs.openstack.org/identity/api/v2.0">
543
        <endpoint "name"="cyclades" "region"="cyclades" "internalURL"="https://node1.example.com/ui/" "adminURL"="https://node1.example.com/ui/" "id"="5" "publicURL"="https://node1.example.com/ui/" />
544
        <endpoint "name"="pithos" "region"="pithos" "internalURL"="https://node2.example.com/ui/" "adminURL"="https://node2.example.com/v1" "id"="6" "publicURL"="https://node2.example.com/ui/" />
545
    </endpoints>
546
    <endpoint_links>
547
            <endpoint_link "href"="/astakos/api/tokens/0000/endpoints?marker=6&amp;limit=10000" "rel"="next" />
548
    </endpoint_links>
549

  
550

  
551
|
552

  
553
=========================== =====================
554
Return Code                 Description
555
=========================== =====================
556
200 (OK)                    The request succeeded
557
400 (Bad Request)           Method not allowed or token does not belong to the specific user
558
401 (Unauthorized)          Missing or expired or invalid service token
559
403 (Forbidden)             Path token does not comply with X-Auth-Token
560
500 (Internal Server Error) The request cannot be completed because of an internal error
561
=========================== =====================
b/snf-astakos-app/astakos/api/keystone_urls.py
36 36
urlpatterns = patterns(
37 37
    'astakos.api.tokens',
38 38
    url(r'tokens/?$', 'authenticate'),
39
    url(r'tokens/(?P<token>.+?)/endpoints', 'get_endpoints'),
40 39
)
b/snf-astakos-app/astakos/api/tokens.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from urlparse import urlunsplit, urlsplit
35 34
from collections import defaultdict
36 35

  
37
from django.http import urlencode
38 36
from django.views.decorators.csrf import csrf_exempt
39 37

  
40 38
from snf_django.lib.api import faults, utils, api_method
41 39

  
42 40
from astakos.im.models import Service, AstakosUser
43
from .util import user_from_token, json_response, xml_response, validate_user
41
from .util import json_response, xml_response, validate_user
44 42

  
45 43
import logging
46 44
logger = logging.getLogger(__name__)
47 45

  
48 46

  
49
@api_method(http_method="GET", token_required=True, user_required=False,
50
            logger=logger)
51
@user_from_token  # Authenticate user!!
52
def get_endpoints(request, token):
53
    if token != request.user.auth_token:
54
        raise faults.Forbidden()
55

  
56
    belongsTo = request.GET.get('belongsTo')
57
    if belongsTo and belongsTo != request.user.uuid:
58
        raise faults.BadRequest()
59

  
60
    marker = request.GET.get('marker', 0)
61
    limit = request.GET.get('limit', 10000)
62

  
63
    endpoints = list(Service.objects.all().order_by('id').
64
                     filter(id__gt=marker)[:limit].
65
                     values('name', 'url', 'api_url', 'id', 'type'))
66
    for e in endpoints:
67
        e['publicURL'] = e['admiURL'] = e['internalURL'] = e['api_url']
68
        e['SNF:uiURL'] = e['url']
69
        e['region'] = e['name']
70
        e.pop('api_url')
71

  
72
    if endpoints:
73
        parts = list(urlsplit(request.path))
74
        params = {'marker': endpoints[-1]['id'], 'limit': limit}
75
        parts[3] = urlencode(params)
76
        next_page_url = urlunsplit(parts)
77
        endpoint_links = [{'href': next_page_url, 'rel': 'next'}]
78
    else:
79
        endpoint_links = []
80

  
81
    result = {'endpoints': endpoints, 'endpoint_links': endpoint_links}
82
    if request.serialization == 'xml':
83
        return xml_response(result, 'api/endpoints.xml')
84
    else:
85
        return json_response(result)
86

  
87

  
88 47
@csrf_exempt
89 48
@api_method(http_method="POST", token_required=False, user_required=False,
90 49
            logger=logger)
b/snf-astakos-app/astakos/im/tests/api.py
36 36
from django.test import TestCase
37 37
from django.core.urlresolvers import reverse
38 38

  
39

  
40
from urllib import quote
41
from urlparse import urlparse, parse_qs
42 39
#from xml.dom import minidom
43 40

  
44 41
import json
......
553 550
#            body = minidom.parseString(r.content)
554 551
#        except Exception, e:
555 552
#            self.fail(e)
556

  
557
    def test_get_endpoints(self):
558
        client = Client()
559

  
560
        # Check in active user token
561
        inactive_user = AstakosUser.objects.create(email='test3')
562
        url = '/astakos/api/tokens/%s/endpoints' % quote(
563
            inactive_user.auth_token)
564
        r = client.get(url)
565
        self.assertEqual(r.status_code, 401)
566

  
567
        # Check invalid user token in path
568
        url = '/astakos/api/tokens/nouser/endpoints'
569
        r = client.get(url)
570
        self.assertEqual(r.status_code, 401)
571

  
572
        # Check forbidden
573
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
574
        headers = {'HTTP_X_AUTH_TOKEN': AstakosUser.objects.create(
575
            email='test4').auth_token}
576
        r = client.get(url, **headers)
577
        self.assertEqual(r.status_code, 401)
578

  
579
        # Check bad request method
580
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
581
        r = client.post(url)
582
        self.assertEqual(r.status_code, 400)
583

  
584
        # Check forbidden
585
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
586
        headers = {'HTTP_X_AUTH_TOKEN': self.user2.auth_token}
587
        r = client.get(url, **headers)
588
        self.assertEqual(r.status_code, 403)
589

  
590
        # Check belongsTo BadRequest
591
        url = '/astakos/api/tokens/%s/endpoints?belongsTo=%s' % (
592
            quote(self.user1.auth_token), quote(self.user2.uuid))
593
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
594
        r = client.get(url, **headers)
595
        self.assertEqual(r.status_code, 400)
596

  
597
        # Check successful request
598
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
599
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
600
        r = client.get(url, **headers)
601
        self.assertEqual(r.status_code, 200)
602
        self.assertEqual(r['Content-Type'], 'application/json; charset=UTF-8')
603
        try:
604
            body = json.loads(r.content)
605
        except:
606
            self.fail('json format expected')
607
        endpoints = body.get('endpoints')
608
        self.assertEqual(len(endpoints), 3)
609

  
610
         # Check xml serialization
611
        url = '/astakos/api/tokens/%s/endpoints?format=xml' %\
612
            quote(self.user1.auth_token)
613
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
614
        r = client.get(url, **headers)
615
        self.assertEqual(r.status_code, 200)
616
        self.assertEqual(r['Content-Type'], 'application/xml; charset=UTF-8')
617
#        try:
618
#            body = minidom.parseString(r.content)
619
#        except Exception, e:
620
#            self.fail('xml format expected')
621
        endpoints = body.get('endpoints')
622
        self.assertEqual(len(endpoints), 3)
623

  
624
        # Check limit
625
        url = '/astakos/api/tokens/%s/endpoints?limit=2' %\
626
            quote(self.user1.auth_token)
627
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
628
        r = client.get(url, **headers)
629
        self.assertEqual(r.status_code, 200)
630
        body = json.loads(r.content)
631
        endpoints = body.get('endpoints')
632
        self.assertEqual(len(endpoints), 2)
633

  
634
        endpoint_link = body.get('endpoint_links', [])[0]
635
        next = endpoint_link.get('href')
636
        p = urlparse(next)
637
        params = parse_qs(p.query)
638
        self.assertTrue('limit' in params)
639
        self.assertTrue('marker' in params)
640
        self.assertEqual(params['marker'][0], '2')
641

  
642
        # Check marker
643
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
644
        r = client.get(next, **headers)
645
        self.assertEqual(r.status_code, 200)
646
        body = json.loads(r.content)
647
        endpoints = body.get('endpoints')
648
        self.assertEqual(len(endpoints), 1)

Also available in: Unified diff