Merge remote-tracking branch 'origin/master' into feature/api-cleanup
diff --git a/xos/api/examples/util.sh b/xos/api/examples/util.sh
index b3d3060..648b32c 100644
--- a/xos/api/examples/util.sh
+++ b/xos/api/examples/util.sh
@@ -41,7 +41,7 @@
     fi
     ID=`echo $JSON | python -c "import json,sys; print json.load(sys.stdin)['related'].get('vsg_id','')"`
     if [[ $ID == "" ]]; then
-        echo "there is no volt for this subscriber" >&2
+        echo "there is no vsg for this subscriber" >&2
         exit -1
     fi
 
diff --git a/xos/api/import_methods.py b/xos/api/import_methods.py
index 1b5e3ca..3702f8a 100644
--- a/xos/api/import_methods.py
+++ b/xos/api/import_methods.py
@@ -30,7 +30,16 @@
 
 def import_module_by_dotted_name(name):
     print "import", name
-    module = __import__(name)
+    try:
+        module = __import__(name)
+    except:
+        # django will eat the exception, and then fail later with
+        #  'conflicting models in application'
+        # when it tries to import the module a second time.
+        print "exception in import_model_by_dotted_name"
+        import traceback
+        traceback.print_exc()
+        raise
     for part in name.split(".")[1:]:
         module = getattr(module, part)
     return module
diff --git a/xos/api/service/vtn.py b/xos/api/service/vtn.py
new file mode 100644
index 0000000..970689f
--- /dev/null
+++ b/xos/api/service/vtn.py
@@ -0,0 +1,65 @@
+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 api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+
+class VTNViewSet(XOSViewSet):
+    base_name = "vtn"
+    method_name = "vtn"
+    method_kind = "viewset"
+
+    # these are just because ViewSet needs some queryset and model, even if we don't use the
+    # default endpoints
+    queryset = Service.objects.none() # CordSubscriber.get_tenant_objects().select_related().all()
+    model = Service
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = [] # super(VTNViewSet, self).get_urlpatterns(api_path=api_path)
+
+        patterns.append( self.list_url("services/$", {"get": "get_services"}, "services") )
+        patterns.append( self.list_url("services_names/$", {"get": "get_services_names"}, "services") )
+        patterns.append( self.list_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "get_service") )
+
+        return patterns
+
+    def get_services_names(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_names():
+               dependencies = service.get_vtn_dependencies_names()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_services(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_ids():
+               dependencies = service.get_vtn_dependencies_ids()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_service(self, request, pk=None, service=None):
+        for xos_service in Service.objects.all():
+            if service in xos_service.get_vtn_src_ids():
+                return Response(xos_service.get_vtn_dependencies_ids())
+        raise DoesNotExist()
+
+    def list(self, request):
+        raise Exception("Not Implemented")
+
diff --git a/xos/api/tenant/cord/vsg.py b/xos/api/tenant/cord/vsg.py
new file mode 100644
index 0000000..6807e98
--- /dev/null
+++ b/xos/api/tenant/cord/vsg.py
@@ -0,0 +1,62 @@
+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 status
+from core.models import *
+from django.forms import widgets
+from services.cord.models import VSGTenant, VSGService, CordSubscriberRoot
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+def get_default_vsg_service():
+    vsg_services = VSGService.get_service_objects().all()
+    if vsg_services:
+        return vsg_services[0].id
+    return None
+
+class VSGTenantForAPI(VSGTenant):
+    class Meta:
+        proxy = True
+        app_label = "cord"
+
+    @property
+    def related(self):
+        related = {}
+        if self.instance:
+            related["instance_id"] = self.instance.id
+        return related
+
+class VSGTenantSerializer(PlusModelSerializer):
+    id = ReadOnlyField()
+    wan_container_ip = serializers.CharField()
+    wan_container_mac = ReadOnlyField()
+    related = serializers.DictField(required=False)
+
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    class Meta:
+        model = VSGTenantForAPI
+        fields = ('humanReadableName', 'id', 'wan_container_ip', 'wan_container_mac', 'related' )
+
+    def getHumanReadableName(self, obj):
+        return obj.__unicode__()
+
+class VSGTenantViewSet(XOSViewSet):
+    base_name = "vsg"
+    method_name = "vsg"
+    method_kind = "viewset"
+    queryset = VSGTenantForAPI.get_tenant_objects().all()
+    serializer_class = VSGTenantSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(VSGTenantViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+
+
+
+
+
diff --git a/xos/api/utility/__init__.py b/xos/api/utility/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/utility/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/utility/loginview.py b/xos/api/utility/loginview.py
new file mode 100644
index 0000000..2dc79c6
--- /dev/null
+++ b/xos/api/utility/loginview.py
@@ -0,0 +1,101 @@
+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.views import APIView
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from django.contrib.contenttypes.models import ContentType
+import json
+import socket
+import time
+import django.middleware.csrf
+from xos.exceptions import *
+from django.contrib.sessions.backends.db import SessionStore
+from django.contrib.sessions.models import Session
+from django.contrib.auth import authenticate
+
+def date_handler(obj):
+    return obj.isoformat() if hasattr(obj, 'isoformat') else obj
+
+def serialize_user(model):
+    serialized = model_to_dict(model)
+    del serialized['timezone']
+    del serialized['password']
+    return json.dumps(serialized, default=date_handler)
+
+class LoginView(APIView):
+    method_kind = "list"
+    method_name = "login"
+
+    def do_login(self, request, username, password):
+        if not username:
+            raise XOSMissingField("No username specified")
+
+        if not password:
+            raise XOSMissingField("No password specified")
+
+        u=authenticate(username=username, password=password)
+        if not u:
+            raise PermissionDenied("Failed to authenticate user %s" % username)
+
+        auth = {"username": username, "password": password}
+        request.session["auth"] = auth
+        request.session['_auth_user_id'] = u.pk
+        request.session['_auth_user_backend'] = u.backend
+        request.session.save()
+
+        return Response({
+            "xoscsrftoken": django.middleware.csrf.get_token(request),
+            "xossessionid": request.session.session_key,
+            "user": serialize_user(u)
+        })
+
+    def get(self, request, format=None):
+        username = request.GET.get("username", None)
+        password = request.GET.get("password", None)
+
+        return self.do_login(request, username, password)
+
+    def post(self, request, format=None):
+        username = request.data.get("username", None)
+        password = request.data.get("password", None)
+
+        return self.do_login(request, username, password)
+
+class LogoutView(APIView):
+    method_kind = "list"
+    method_name = "logout"
+
+    def do_logout(self, request, sessionid):
+        if not sessionid:
+            raise XOSMissingField("No xossessionid specified")
+
+        # Make sure the session exists. This prevents us from accidentally
+        # creating empty sessions with SessionStore()
+        session = Session.objects.filter(session_key=sessionid)
+        if not session:
+            # session doesn't exist
+            raise PermissionDenied("Session does not exist")
+
+        session = SessionStore(session_key=sessionid)
+        if "auth" in session:
+            del session["auth"]
+            session.save()
+        if "_auth_user_id" in session:
+            del session["_auth_user_id"]
+            session.save()
+
+        return Response("Logged Out")
+
+    def get(self, request, format=None):
+        sessionid = request.GET.get("xossessionid", None)
+        return self.do_logout(request, sessionid)
+
+    def post(self, request, format=None):
+        sessionid = request.data.get("xossessionid", None)
+        return self.do_logout(request, sessionid)
\ No newline at end of file
diff --git a/xos/core/xoslib/methods/loginview.py b/xos/core/xoslib/methods/loginview.py
old mode 100755
new mode 100644
index 69ee289..2dc79c6
--- a/xos/core/xoslib/methods/loginview.py
+++ b/xos/core/xoslib/methods/loginview.py
@@ -62,8 +62,8 @@
         return self.do_login(request, username, password)
 
     def post(self, request, format=None):
-        username = request.DATA.get("username", None)
-        password = request.DATA.get("password", None)
+        username = request.data.get("username", None)
+        password = request.data.get("password", None)
 
         return self.do_login(request, username, password)
 
@@ -97,5 +97,5 @@
         return self.do_logout(request, sessionid)
 
     def post(self, request, format=None):
-        sessionid = request.DATA.get("xossessionid", None)
+        sessionid = request.data.get("xossessionid", None)
         return self.do_logout(request, sessionid)
\ No newline at end of file
diff --git a/xos/core/xoslib/methods/vtn.py b/xos/core/xoslib/methods/vtn.py
index c9dbf3a..968922e 100644
--- a/xos/core/xoslib/methods/vtn.py
+++ b/xos/core/xoslib/methods/vtn.py
@@ -16,6 +16,9 @@
 import json
 import subprocess
 
+class VTNSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+
 class VTNViewSet(XOSViewSet):
     base_name = "vtn"
     method_name = "rs/vtn"
@@ -26,6 +29,8 @@
     queryset = Service.objects.none() # CordSubscriber.get_tenant_objects().select_related().all()
     model = Service
 
+    serializer_class = VTNSerializer
+
     @classmethod
     def get_urlpatterns(self):
         patterns = []