API refactor WIP
diff --git a/xos/api/cord/debug.py b/xos/api/cord/debug.py
new file mode 100644
index 0000000..da22d96
--- /dev/null
+++ b/xos/api/cord/debug.py
@@ -0,0 +1,61 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import viewsets
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from services.cord.models import VOLTTenant, VBNGTenant, CordSubscriberRoot
+from core.xoslib.objects.cordsubscriber import CordSubscriber
+from api.xosapi_helpers import PlusSerializerMixin, XOSViewSet
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+
+if hasattr(serializers, "ReadOnlyField"):
+ # rest_framework 3.x
+ ReadOnlyField = serializers.ReadOnlyField
+else:
+ # rest_framework 2.x
+ ReadOnlyField = serializers.Field
+
+class CordDebugIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
+ # Swagger is failing because CordDebugViewSet has neither a model nor
+ # a serializer_class. Stuck this in here as a placeholder for now.
+ id = ReadOnlyField()
+ class Meta:
+ model = CordSubscriber
+
+class CordDebugViewSet(XOSViewSet):
+ base_name = "debug"
+ method_name = "debug"
+ method_kind = "viewset"
+ serializer_class = CordDebugIdSerializer
+
+ @classmethod
+ def get_urlpatterns(self, api_path=""):
+ patterns = []
+ patterns.append( url("^" + api_path + "debug/vbng_dump/$", self.as_view({"get": "get_vbng_dump"}), name="vbng_dump"))
+ return patterns
+
+ # contact vBNG service and dump current list of mappings
+ def get_vbng_dump(self, request, pk=None):
+ result=subprocess.check_output(["curl", "http://10.0.3.136:8181/onos/virtualbng/privateip/map"])
+ if request.GET.get("theformat",None)=="text":
+ from django.http import HttpResponse
+ result = json.loads(result)["map"]
+
+ lines = []
+ for row in result:
+ for k in row.keys():
+ lines.append( "%s %s" % (k, row[k]) )
+
+ return HttpResponse("\n".join(lines), content_type="text/plain")
+ else:
+ return Response( {"vbng_dump": json.loads(result)["map"] } )
diff --git a/xos/api/cord/subscriber.py b/xos/api/cord/subscriber.py
index f0bee26..ac19420 100644
--- a/xos/api/cord/subscriber.py
+++ b/xos/api/cord/subscriber.py
@@ -11,7 +11,7 @@
from django.conf.urls import patterns, url
from services.cord.models import VOLTTenant, VBNGTenant, CordSubscriberRoot
from core.xoslib.objects.cordsubscriber import CordSubscriber
-from plus import PlusSerializerMixin, XOSViewSet
+from api.xosapi_helpers import PlusSerializerMixin, XOSViewSet
from django.shortcuts import get_object_or_404
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
from xos.exceptions import *
@@ -101,70 +101,6 @@
method_kind = "detail"
method_name = "cordsubscriber"
-# We fake a user object by pulling the user data struct out of the
-# subscriber object...
-
-def serialize_user(subscriber, user):
- return {"id": "%d-%d" % (subscriber.id, user["id"]),
- "name": user["name"],
- "level": user.get("level",""),
- "mac": user.get("mac", ""),
- "subscriber": subscriber.id }
-
-class CordUserList(APIView):
- method_kind = "list"
- method_name = "corduser"
-
- def get(self, request, format=None):
- instances=[]
- for subscriber in CordSubscriber.get_tenant_objects().all():
- for user in subscriber.users:
- instances.append( serialize_user(subscriber, user) )
-
- return Response(instances)
-
- def post(self, request, format=None):
- data = request.DATA
- subscriber = CordSubscriber.get_tenant_objects().get(id=int(data["subscriber"]))
- user = subscriber.create_user(name=data["name"],
- level=data["level"],
- mac=data["mac"])
- subscriber.save()
-
- return Response(serialize_user(subscriber,user))
-
-class CordUserDetail(APIView):
- method_kind = "detail"
- method_name = "corduser"
-
- def get(self, request, format=None, pk=0):
- parts = pk.split("-")
- subscriber = CordSubscriber.get_tenant_objects().filter(id=parts[0])
- for user in subscriber.users:
- return Response( [ serialize_user(subscriber, user) ] )
- raise XOSNotFound("Failed to find user %s" % pk)
-
- def delete(self, request, pk):
- parts = pk.split("-")
- subscriber = CordSubscriber.get_tenant_objects().get(id=int(parts[0]))
- subscriber.delete_user(parts[1])
- subscriber.save()
- return Response("okay")
-
- def put(self, request, pk):
- kwargs={}
- if "name" in request.DATA:
- kwargs["name"] = request.DATA["name"]
- if "level" in request.DATA:
- kwargs["level"] = request.DATA["level"]
- if "mac" in request.DATA:
- kwargs["mac"] = request.DATA["mac"]
-
- parts = pk.split("-")
- subscriber = CordSubscriber.get_tenant_objects().get(id=int(parts[0]))
- user = subscriber.update_user(parts[1], **kwargs)
- subscriber.save()
- return Response(serialize_user(subscriber,user))
#------------------------------------------------------------------------------
# The "new" API with many more REST endpoints.
@@ -173,7 +109,7 @@
class CordSubscriberViewSet(XOSViewSet):
base_name = "subscriber"
- method_name = "rs/subscriber"
+ method_name = "subscriber"
method_kind = "viewset"
queryset = CordSubscriber.get_tenant_objects().select_related().all()
serializer_class = CordSubscriberIdSerializer
@@ -185,8 +121,8 @@
return subscriber.vcpe
@classmethod
- def get_urlpatterns(self):
- patterns = super(CordSubscriberViewSet, self).get_urlpatterns()
+ def get_urlpatterns(self, api_path=""):
+ patterns = super(CordSubscriberViewSet, self).get_urlpatterns(api_path=api_path)
patterns.append( self.detail_url("vcpe_synced/$", {"get": "get_vcpe_synced"}, "vcpe_synced") )
patterns.append( self.detail_url("url_filter/$", {"get": "get_url_filter"}, "url_filter") )
patterns.append( self.detail_url("url_filter/(?P<level>[a-zA-Z0-9\-_]+)/$", {"put": "set_url_filter"}, "url_filter") )
@@ -204,12 +140,8 @@
patterns.append( self.detail_url("bbsdump/$", {"get": "get_bbsdump"}, "bbsdump") )
- patterns.append( url("^rs/initdemo/$", self.as_view({"put": "initdemo", "get": "initdemo"}), name="initdemo") )
-
- patterns.append( url("^rs/subidlookup/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") )
- patterns.append( url("^rs/subidlookup/$", self.as_view({"get": "ssidlist"}), name="ssidlist") )
-
- patterns.append( url("^rs/vbng_mapping/$", self.as_view({"get": "get_vbng_mapping"}), name="vbng_mapping") )
+ patterns.append( url(self.api_path + "subidlookup/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") )
+ patterns.append( url(self.api_path + "subidlookup/$", self.as_view({"get": "ssidlist"}), name="ssidlist") )
return patterns
@@ -368,47 +300,3 @@
return Response( ssidmap[0] )
- def get_vbng_mapping(self, request):
- object_list = VBNGTenant.get_tenant_objects().all()
-
- mappings = []
- for vbng in object_list:
- if vbng.mapped_ip and vbng.routeable_subnet:
- mappings.append( {"private_ip": vbng.mapped_ip, "routeable_subnet": vbng.routeable_subnet, "mac": vbng.mapped_mac, "hostname": vbng.mapped_hostname} )
-
- return Response( {"vbng_mapping": mappings} )
-
-class CordDebugIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
- # Swagger is failing because CordDebugViewSet has neither a model nor
- # a serializer_class. Stuck this in here as a placeholder for now.
- id = ReadOnlyField()
- class Meta:
- model = CordSubscriber
-
-class CordDebugViewSet(XOSViewSet):
- base_name = "cord_debug"
- method_name = "rs/cord_debug"
- method_kind = "viewset"
- serializer_class = CordDebugIdSerializer
-
- @classmethod
- def get_urlpatterns(self):
- patterns = []
- patterns.append( url("^rs/cord_debug/vbng_dump/$", self.as_view({"get": "get_vbng_dump"}), name="vbng_dump"))
- return patterns
-
- # contact vBNG service and dump current list of mappings
- def get_vbng_dump(self, request, pk=None):
- result=subprocess.check_output(["curl", "http://10.0.3.136:8181/onos/virtualbng/privateip/map"])
- if request.GET.get("theformat",None)=="text":
- from django.http import HttpResponse
- result = json.loads(result)["map"]
-
- lines = []
- for row in result:
- for k in row.keys():
- lines.append( "%s %s" % (k, row[k]) )
-
- return HttpResponse("\n".join(lines), content_type="text/plain")
- else:
- return Response( {"vbng_dump": json.loads(result)["map"] } )
diff --git a/xos/api/import_methods.py b/xos/api/import_methods.py
index abc62f7..a60b62d 100644
--- a/xos/api/import_methods.py
+++ b/xos/api/import_methods.py
@@ -1,17 +1,19 @@
from django.views.generic import View
-from django.conf.urls import patterns, url
+from django.conf.urls import patterns, url, include
from rest_framework.routers import DefaultRouter
import os, sys
import inspect
import importlib
-def import_module_from_filename(pathname):
+urlpatterns = []
+
+def import_module_from_filename(dirname, fn):
sys_path_save = sys.path
try:
# __import__() and importlib.import_module() both import modules from
# sys.path. So we make sure that the path where we can find the views is
# the first thing in sys.path.
- sys.path = [dir] + sys.path
+ sys.path = [dirname] + sys.path
module = __import__(fn[:-3])
finally:
@@ -19,17 +21,18 @@
return module
-def import_methods(dir=None, api_path="api"):
- urlpatterns=[]
+def import_api_methods(dirname=None, api_path="api"):
subdirs=[]
+ urlpatterns=[]
- if not dir:
- dir = os.path.dirname(os.path.abspath(__file__))
+ if not dirname:
+ dirname = os.path.dirname(os.path.abspath(__file__))
- for fn in os.listdir(dir):
- pathname = os.path.join(dir,fn)
+ view_urls = []
+ for fn in os.listdir(dirname):
+ pathname = os.path.join(dirname,fn)
if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
- module = import_module_from_filename(fn[:-3])
+ module = import_module_from_filename(dirname, fn)
for classname in dir(module):
c = getattr(module, classname, None)
@@ -37,12 +40,13 @@
globals()[classname] = c
method_kind = getattr(c, "method_kind", None)
- method_name = os.path.join(api_path, getattr(c, "method_name", None))
+ method_name = getattr(c, "method_name", None)
if method_kind and method_name:
+ method_name = os.path.join(api_path, method_name)
view_urls.append( (method_kind, method_name, classname, c) )
elif os.path.isdir(pathname):
- urlpatterns.extend(import_methods(os.path.append(dir, fn), os.path.append(api_path, fn)))
+ urlpatterns.extend(import_api_methods(pathname, os.path.join(api_path, fn)))
for view_url in view_urls:
if view_url[0] == "list":
@@ -51,7 +55,9 @@
urlpatterns.append(url(r'^' + view_url[1] + '/(?P<pk>[a-zA-Z0-9\-]+)/$', view_url[3].as_view(), name=view_url[1]+'detail'))
elif view_url[0] == "viewset":
viewset = view_url[3]
-
- urlpatterns.extend(viewset.get_urlpatterns())
+ urlpatterns.extend(viewset.get_urlpatterns(api_path=api_path+"/"))
return urlpatterns
+
+urlpatterns = import_api_methods()
+
diff --git a/xos/api/plus.py b/xos/api/xosapi_helpers.py
similarity index 70%
rename from xos/api/plus.py
rename to xos/api/xosapi_helpers.py
index 294fba8..69156af 100644
--- a/xos/api/plus.py
+++ b/xos/api/xosapi_helpers.py
@@ -29,23 +29,27 @@
return obj.getBackendHtml()
class XOSViewSet(viewsets.ModelViewSet):
+ api_path=""
+
@classmethod
def detail_url(self, pattern, viewdict, name):
- return url(r'^' + self.method_name + r'/(?P<pk>[a-zA-Z0-9\-]+)/' + pattern,
+ return url(r'^' + self.api_path + self.method_name + r'/(?P<pk>[a-zA-Z0-9\-]+)/' + pattern,
self.as_view(viewdict),
name=self.base_name+"_"+name)
@classmethod
def list_url(self, pattern, viewdict, name):
- return url(r'^' + self.method_name + r'/' + pattern,
+ return url(r'^' + self.api_path + self.method_name + r'/' + pattern,
self.as_view(viewdict),
name=self.base_name+"_"+name)
@classmethod
- def get_urlpatterns(self):
+ def get_urlpatterns(self, api_path=""):
+ self.api_path = api_path
+
patterns = []
- patterns.append(url(r'^' + self.method_name + '/$', self.as_view({'get': 'list'}), name=self.base_name+'_list'))
- patterns.append(url(r'^' + self.method_name + '/(?P<pk>[a-zA-Z0-9\-]+)/$', self.as_view({'get': 'retrieve', 'put': 'update', 'post': 'update', 'delete': 'destroy', 'patch': 'partial_update'}), name=self.base_name+'_detail'))
+ patterns.append(url(r'^' + self.api_path + self.method_name + '/$', self.as_view({'get': 'list'}), name=self.base_name+'_list'))
+ patterns.append(url(r'^' + self.api_path + self.method_name + '/(?P<pk>[a-zA-Z0-9\-]+)/$', self.as_view({'get': 'retrieve', 'put': 'update', 'post': 'update', 'delete': 'destroy', 'patch': 'partial_update'}), name=self.base_name+'_detail'))
return patterns
diff --git a/xos/xos/urls.py b/xos/xos/urls.py
index 4c3f07d..1bc3885 100644
--- a/xos/xos/urls.py
+++ b/xos/xos/urls.py
@@ -10,12 +10,11 @@
from core.views.legacyapi import LegacyXMLRPC
from core.views.serviceGraph import ServiceGridView, ServiceGraphView
from services.helloworld.view import *
-#from core.views.analytics import AnalyticsAjaxView
from core.models import *
from rest_framework import generics
from core.dashboard.sites import SitePlus
from django.http import HttpResponseRedirect
-#from core.xoslib import XOSLibDataView
+#from api import import_api_methods
admin.site = SitePlus()
admin.autodiscover()
@@ -43,18 +42,17 @@
url(r'^', include(admin.site.urls)),
#url(r'^profile/home', 'core.views.home'),
-# url(r'^admin/xoslib/(?P<name>\w+)/$', XOSLibDataView.as_view(), name="xoslib"),
-
url(r'^xmlrpc/legacyapi/$', 'core.views.legacyapi.LegacyXMLRPC', name='xmlrpc'),
-# url(r'^analytics/(?P<name>\w+)/$', AnalyticsAjaxView.as_view(), name="analytics"),
-
url(r'^files/', redirect_to_apache),
- #Adding in rest_framework urls
+ # Adding in rest_framework urls
url(r'^xos/', include('rest_framework.urls', namespace='rest_framework')),
- # XOSLib rest methods
+ # XOSLib rest methods [deprecated]
url(r'^xoslib/', include('core.xoslib.methods', namespace='xoslib')),
+
+ url(r'^', include('api.import_methods', namespace='api')),
+
) + get_REST_patterns() + get_hpc_REST_patterns()