CORD-967 Translate XOS Exceptions to gRPC status codes
Change-Id: I27d4b224e0c795d036747a814852b99834445829
diff --git a/xos/coreapi/apihelper.py b/xos/coreapi/apihelper.py
index b69ea72..a2a2a95 100644
--- a/xos/coreapi/apihelper.py
+++ b/xos/coreapi/apihelper.py
@@ -5,6 +5,7 @@
import time
from protos import xos_pb2
from google.protobuf.empty_pb2 import Empty
+import grpc
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import authenticate as django_authenticate
@@ -16,6 +17,25 @@
from django.conf import settings
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
+def translate_exceptions(function):
+ def wrapper(*args, **kwargs):
+ try:
+ return function(*args, **kwargs)
+ except Exception, e:
+ if "context" in kwargs:
+ context = kwargs["context"]
+ else:
+ context = args[2]
+ context.set_details(str(e))
+ if (type(e) == XOSPermissionDenied):
+ context.set_code(grpc.StatusCode.PERMISSION_DENIED)
+ elif (type(e) == XOSValidationError):
+ context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
+ elif (type(e) == XOSNotAuthenticated):
+ context.set_code(grpc.StatusCode.UNAUTHENTICATED)
+ raise
+ return wrapper
+
class XOSAPIHelperMixin(object):
def __init__(self):
import django.apps
diff --git a/xos/coreapi/xos_utility_api.py b/xos/coreapi/xos_utility_api.py
index 937bdaf..d9c3a92 100644
--- a/xos/coreapi/xos_utility_api.py
+++ b/xos/coreapi/xos_utility_api.py
@@ -16,7 +16,7 @@
from django.db.models import F,Q
from core.models import *
from xos.exceptions import *
-from apihelper import XOSAPIHelperMixin
+from apihelper import XOSAPIHelperMixin, translate_exceptions
# The Tosca engine expects to be run from /opt/xos/tosca/ or equivalent. It
# needs some sys.path fixing up.
@@ -45,13 +45,14 @@
def stop(self):
pass
+ @translate_exceptions
def Login(self, request, context):
if not request.username:
- raise XOSPermissionDenied("No username")
+ raise XOSNotAuthenticated("No username")
u=django_authenticate(username=request.username, password=request.password)
if not u:
- raise XOSPermissionDenied("Failed to authenticate user %s" % request.username)
+ raise XOSNotAuthenticated("Failed to authenticate user %s" % request.username)
session = SessionStore()
auth = {"username": request.username, "password": request.password}
@@ -65,6 +66,7 @@
return response
+ @translate_exceptions
def Logout(self, request, context):
for (k, v) in context.invocation_metadata():
if (k.lower()=="x-xossession"):
@@ -74,6 +76,7 @@
s.save()
return Empty()
+ @translate_exceptions
def RunTosca(self, request, context):
user=self.authenticate(context, required=True)
@@ -97,6 +100,7 @@
return response
+ @translate_exceptions
def DestroyTosca(self, request, context):
user=self.authenticate(context, required=True)
@@ -120,9 +124,11 @@
return response
+ @translate_exceptions
def NoOp(self, request, context):
return Empty()
+ @translate_exceptions
def ListDirtyModels(self, request, context):
dirty_models = utility_pb2.ModelList()
@@ -143,6 +149,7 @@
return dirty_models
+ @translate_exceptions
def SetDirtyModels(self, request, context):
user=self.authenticate(context, required=True)
diff --git a/xos/tools/apigen/grpc_api.template.py b/xos/tools/apigen/grpc_api.template.py
index b8dcc59..90009eb 100644
--- a/xos/tools/apigen/grpc_api.template.py
+++ b/xos/tools/apigen/grpc_api.template.py
@@ -5,7 +5,7 @@
from django.contrib.auth import authenticate as django_authenticate
from xos.exceptions import *
-from apihelper import XOSAPIHelperMixin
+from apihelper import XOSAPIHelperMixin, translate_exceptions
class XosService(xos_pb2.xosServicer, XOSAPIHelperMixin):
def __init__(self, thread_pool):
@@ -16,31 +16,37 @@
pass
{% for object in generator.all() %}
+ @translate_exceptions
def List{{ object.camel() }}(self, request, context):
user=self.authenticate(context)
model=self.get_model("{{ object.camel() }}")
return self.querysetToProto(model, model.objects.all())
+ @translate_exceptions
def Filter{{ object.camel() }}(self, request, context):
user=self.authenticate(context)
model=self.get_model("{{ object.camel() }}")
return self.filter(model, request)
+ @translate_exceptions
def Get{{ object.camel() }}(self, request, context):
user=self.authenticate(context)
model=self.get_model("{{ object.camel() }}")
return self.get(model, request.id)
+ @translate_exceptions
def Create{{ object.camel() }}(self, request, context):
user=self.authenticate(context)
model=self.get_model("{{ object.camel() }}")
return self.create(model, user, request)
+ @translate_exceptions
def Delete{{ object.camel() }}(self, request, context):
user=self.authenticate(context)
model=self.get_model("{{ object.camel() }}")
return self.delete(model, user, request.id)
+ @translate_exceptions
def Update{{ object.camel() }}(self, request, context):
user=self.authenticate(context)
model=self.get_model("{{ object.camel() }}")