blob: d48ad4eb3d067d3807d70a378f6e2b081232deb3 [file] [log] [blame]
# Copyright 2017-present Open Networking Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import base64
import fnmatch
import os
import sys
import time
import traceback
from protos import utility_pb2, utility_pb2_grpc
from google.protobuf.empty_pb2 import Empty
from importlib import import_module
from django.conf import settings
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
from django.contrib.auth import authenticate as django_authenticate
import django.apps
from django.db.models import F,Q
from core.models import *
from xos.exceptions import *
from apihelper import XOSAPIHelperMixin, translate_exceptions
import grpc
from apistats import REQUEST_COUNT, track_request_time
# The Tosca engine expects to be run from /opt/xos/tosca/ or equivalent. It
# needs some sys.path fixing up.
import inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
toscadir = os.path.join(currentdir, "../tosca")
def is_internal_model(model):
""" things to be excluded from the dirty_models endpoints """
if 'django' in model.__module__:
return True
if 'cors' in model.__module__:
return True
if 'contenttypes' in model.__module__:
return True
if 'core.models.journal' in model.__module__: # why?
return True
if 'core.models.project' in model.__module__: # why?
return True
return False
def get_xproto(folder):
matches = []
for root, dirnames, filenames in os.walk(folder):
for filename in fnmatch.filter(filenames, '*.xproto'):
matches.append(os.path.join(root, filename))
return matches
class UtilityService(utility_pb2_grpc.utilityServicer, XOSAPIHelperMixin):
def __init__(self, thread_pool):
self.thread_pool = thread_pool
XOSAPIHelperMixin.__init__(self)
def stop(self):
pass
@translate_exceptions("Utilities", "Login")
@track_request_time("Utilities", "Login")
def Login(self, request, context):
if not request.username:
raise XOSNotAuthenticated("No username")
u=django_authenticate(username=request.username, password=request.password)
if not u:
raise XOSNotAuthenticated("Failed to authenticate user %s" % request.username)
session = SessionStore()
auth = {"username": request.username, "password": request.password}
session["auth"] = auth
session['_auth_user_id'] = u.pk
session['_auth_user_backend'] = u.backend
session.save()
response = utility_pb2.LoginResponse()
response.sessionid = session.session_key
REQUEST_COUNT.labels('xos-core', "Utilities", "Login", grpc.StatusCode.OK).inc()
return response
@translate_exceptions("Utilities", "Logout")
@track_request_time("Utilities", "Logout")
def Logout(self, request, context):
for (k, v) in context.invocation_metadata():
if (k.lower()=="x-xossession"):
s = SessionStore(session_key=v)
if "_auth_user_id" in s:
del s["_auth_user_id"]
s.save()
REQUEST_COUNT.labels('xos-core', "Utilities", "Login", grpc.StatusCode.OK).inc()
return Empty()
# FIXME are we still using these?
@translate_exceptions("Utilities", "RunTosca")
@track_request_time("Utilities", "RunTosca")
def RunTosca(self, request, context):
user=self.authenticate(context, required=True)
sys_path_save = sys.path
try:
sys.path.append(toscadir)
from tosca.engine import XOSTosca
xt = XOSTosca(request.recipe, parent_dir=toscadir, log_to_console=False)
xt.execute(user)
except:
response = utility_pb2.ToscaResponse()
response.status = response.ERROR
response.messages = traceback.format_exc()
return response
finally:
sys.path = sys_path_save
response = utility_pb2.ToscaResponse()
response.status = response.SUCCESS
response.messages = "\n".join(xt.log_msgs)
return response
@translate_exceptions("Utilities", "DestryTosca")
@track_request_time("Utilities", "DestryTosca")
def DestroyTosca(self, request, context):
user=self.authenticate(context, required=True)
sys_path_save = sys.path
try:
sys.path.append(toscadir)
from tosca.engine import XOSTosca
xt = XOSTosca(request.recipe, parent_dir=toscadir, log_to_console=False)
xt.destroy(user)
except:
response = utility_pb2.ToscaResponse()
response.status = response.ERROR
response.messages = traceback.format_exc()
return response
finally:
sys.path = sys_path_save
response = utility_pb2.ToscaResponse()
response.status = response.SUCCESS
response.messages = "\n".join(xt.log_msgs)
return response
# end FIXME
@translate_exceptions("Utilities", "NoOp")
@track_request_time("Utilities", "NoOp")
def NoOp(self, request, context):
REQUEST_COUNT.labels('xos-core', "Utilities", "NoOp", grpc.StatusCode.OK).inc()
return Empty()
@translate_exceptions("Utilities", "AuthenticatedNoOp")
@track_request_time("Utilities", "AuthenticatedNoOp")
def AuthenticatedNoOp(self, request, context):
self.authenticate(context, required=True)
REQUEST_COUNT.labels('xos-core', "Utilities", "AuthenticatedNoOp", grpc.StatusCode.OK).inc()
return Empty()
@translate_exceptions("Utilities", "ListDirtyModels")
@track_request_time("Utilities", "ListDirtyModels")
def ListDirtyModels(self, request, context):
dirty_models = utility_pb2.ModelList()
models = django.apps.apps.get_models()
for model in models:
if is_internal_model(model):
continue
fieldNames = [x.name for x in model._meta.fields]
if (not "enacted" in fieldNames) or (not "updated" in fieldNames):
continue
if (request.class_name) and (not fnmatch.fnmatch(model.__name__, request.class_name)):
continue
objs = model.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
for obj in objs:
item = dirty_models.items.add()
item.class_name = model.__name__
item.id = obj.id
REQUEST_COUNT.labels('xos-core', "Utilities", "ListDirtyModels", grpc.StatusCode.OK).inc()
return dirty_models
@translate_exceptions("Utilities", "SetDirtyModels")
@track_request_time("Utilities", "SetDirtyModels")
def SetDirtyModels(self, request, context):
user=self.authenticate(context, required=True)
dirty_models = utility_pb2.ModelList()
models = django.apps.apps.get_models()
for model in models:
if is_internal_model(model):
continue
fieldNames = [x.name for x in model._meta.fields]
if (not "enacted" in fieldNames) or (not "updated" in fieldNames):
continue
if (request.class_name) and (not fnmatch.fnmatch(model.__name__, request.class_name)):
continue
objs = model.objects.all()
for obj in objs:
try:
obj.caller = user
obj.save()
item = dirty_models.items.add()
item.class_name = model.__name__
item.id = obj.id
except Exception, e:
item = dirty_models.items.add()
item.class_name = model.__name__
item.id = obj.id
item.info = str(e)
REQUEST_COUNT.labels('xos-core', "Utilities", "SetDirtyModels", grpc.StatusCode.OK).inc()
return dirty_models
@translate_exceptions("Utilities", "GetXproto")
@track_request_time("Utilities", "GetXproto")
def GetXproto(self, request, context):
res = utility_pb2.XProtos()
core_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../core/models/')
core_xprotos = get_xproto(core_dir)
service_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../services')
services_xprotos = get_xproto(service_dir)
dynamic_service_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../dynamic_services')
dynamic_services_xprotos = get_xproto(dynamic_service_dir)
xprotos = core_xprotos + services_xprotos + dynamic_services_xprotos
xproto = ""
for f in xprotos:
content = open(f).read()
xproto += "\n"
xproto += content
res.xproto = xproto
REQUEST_COUNT.labels('xos-core', "Utilities", "GetXproto", grpc.StatusCode.OK).inc()
return res
@translate_exceptions("Utilities", "GetPopulatedServiceInstances")
@track_request_time("Utilities", "GetPopulatedServiceInstances")
def GetPopulatedServiceInstances(self, request, context):
"""
Return a service instance with provider and subsciber service instance ids
"""
response = utility_pb2.PopulatedServiceInstance()
si = ServiceInstance.objects.get(id=request.id)
# populate the response object
response.id = si.id
response.leaf_model_name = si.leaf_model_name
response.owner_id = si.owner_id
if si.name:
response.name = si.name
# find links
provided_links = si.provided_links.all()
subscribed_links = si.subscribed_links.all()
# import pdb; pdb.set_trace()
for l in provided_links:
response.provided_service_instances.append(l.subscriber_service_instance.id)
for l in subscribed_links:
if l.subscriber_service_instance:
response.subscribed_service_instances.append(l.provider_service_instance_id)
elif l.subscriber_service:
response.subscribed_service.append(l.subscriber_service.id)
elif l.subscriber_network:
response.subscribed_network.append(l.subscriber_network.id)
REQUEST_COUNT.labels('xos-core', "Utilities", "GetPopulatedServiceInstances", grpc.StatusCode.OK).inc()
return response