CORD-1250 Update to new Service/Tenancy models

Change-Id: I37e73892af3d33163d60cc0095d9bf8368ec3e22
diff --git a/xos/admin.py b/xos/admin.py
index d485b9a..f8bd1ca 100644
--- a/xos/admin.py
+++ b/xos/admin.py
@@ -10,7 +10,7 @@
 from django.utils import timezone
 from django.contrib.contenttypes import generic
 from suit.widgets import LinkedSelect
-from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline, TenantAttrAsTabInline
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, ServiceInstanceAttrAsTabInline, SubscriberLinkInline, ProviderLinkInline, ProviderDependencyInline,SubscriberDependencyInline
 from core.middleware import get_request
 
 from functools import update_wrapper
@@ -26,7 +26,7 @@
     list_display_links = ('backend_status_icon', 'name', )
     fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url", "rest_hostname", "rest_port", "no_container" ], 'classes':['suit-tab suit-tab-general']})]
     readonly_fields = ('backend_status_text', )
-    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline, ProviderDependencyInline,SubscriberDependencyInline]
 
     extracontext_registered_admins = True
 
@@ -36,6 +36,7 @@
         ('administration', 'Administration'),
         ('slices','Slices'),
         ('serviceattrs','Additional Attributes'),
+        ('servicetenants', 'Dependencies'),
         ('serviceprivileges','Privileges'),
     )
 
@@ -48,14 +49,14 @@
 class ONOSAppForm(forms.ModelForm):
     def __init__(self,*args,**kwargs):
         super (ONOSAppForm,self ).__init__(*args,**kwargs)
-        self.fields['kind'].widget.attrs['readonly'] = True
-        self.fields['provider_service'].queryset = ONOSService.objects.all()
+#        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['owner'].queryset = ONOSService.objects.all()
         if (not self.instance) or (not self.instance.pk):
             # default fields for an 'add' form
-            self.fields['kind'].initial = ONOS_KIND
-            self.fields['creator'].initial = get_request().user
+#            self.fields['kind'].initial = ONOS_KIND
+#            self.fields['creator'].initial = get_request().user
             if ONOSService.objects.exists():
-               self.fields["provider_service"].initial = ONOSService.objects.all()[0]
+               self.fields["owner"].initial = ONOSService.objects.all()[0]
 
     def save(self, commit=True):
         return super(ONOSAppForm, self).save(commit=commit)
@@ -67,14 +68,13 @@
 class ONOSAppAdmin(ReadOnlyAwareAdmin):
     list_display = ('backend_status_icon', 'name', )
     list_display_links = ('backend_status_icon', 'name')
-    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'name', 'provider_service', 'subscriber_service', 'service_specific_attribute', "dependencies",
-                                     'creator'],
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'name', 'owner', 'service_specific_attribute', "dependencies"],
                           'classes':['suit-tab suit-tab-general']})]
-    readonly_fields = ('backend_status_text', 'instance', 'service_specific_attribute')
-    inlines = [TenantAttrAsTabInline]
+    readonly_fields = ('backend_status_text', 'service_specific_attribute')
+    inlines = [ServiceInstanceAttrAsTabInline, ProviderLinkInline, SubscriberLinkInline]
     form = ONOSAppForm
 
-    suit_form_tabs = (('general','Details'), ('tenantattrs', 'Attributes'))
+    suit_form_tabs = (('general','Details'), ('serviceinstanceattrs', 'Attributes'), ('servicelinks','Links'),)
 
     def get_queryset(self, request):
         return ONOSApp.select_by_user(request.user)
diff --git a/xos/api/service/onos.py b/xos/api/service/onos.py
deleted file mode 100644
index 5861947..0000000
--- a/xos/api/service/onos.py
+++ /dev/null
@@ -1,87 +0,0 @@
-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.onos.models import ONOSService
-from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
-from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
-
-class ONOSServiceSerializer(PlusModelSerializer):
-    id = ReadOnlyField()
-    rest_hostname = serializers.CharField(required=False)
-    rest_port = serializers.CharField(default="8181")
-    no_container = serializers.BooleanField(default=False)
-    node_key = serializers.CharField(required=False)
-
-    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
-    class Meta:
-        model = ONOSService
-        fields = ('humanReadableName', 'id', 'rest_hostname', 'rest_port', 'no_container', 'node_key')
-
-    def getHumanReadableName(self, obj):
-        return obj.__unicode__()
-
-class ServiceAttributeSerializer(serializers.Serializer):
-    id = ReadOnlyField()
-    name = serializers.CharField(required=False)
-    value = serializers.CharField(required=False)
-
-class ONOSServiceViewSet(XOSViewSet):
-    base_name = "onos"
-    method_name = "onos"
-    method_kind = "viewset"
-    queryset = ONOSService.objects.all()
-    serializer_class = ONOSServiceSerializer
-
-    custom_serializers = {"set_attribute": ServiceAttributeSerializer}
-
-    @classmethod
-    def get_urlpatterns(self, api_path="^"):
-        patterns = super(ONOSServiceViewSet, self).get_urlpatterns(api_path=api_path)
-
-        patterns.append( self.detail_url("attributes/$", {"get": "get_attributes", "post": "add_attribute"}, "attributes") )
-        patterns.append( self.detail_url("attributes/(?P<attribute>[0-9]+)/$", {"get": "get_attribute", "put": "set_attribute", "delete": "delete_attribute"}, "attribute") )
-
-        return patterns
-
-    def get_attributes(self, request, pk=None):
-        svc = self.get_object()
-        return Response(ServiceAttributeSerializer(svc.serviceattributes.all(), many=True).data)
-
-    def add_attribute(self, request, pk=None):
-        svc = self.get_object()
-        ser = ServiceAttributeSerializer(data=request.data)
-        ser.is_valid(raise_exception = True)
-        att = ServiceAttribute(service=svc, **ser.validated_data)
-        att.save()
-        return Response(ServiceAttributeSerializer(att).data)
-
-    def get_attribute(self, request, pk=None, attribute=None):
-        svc = self.get_object()
-        att = ServiceAttribute.objects.get(pk=attribute)
-        return Response(ServiceAttributeSerializer(att).data)
-
-    def set_attribute(self, request, pk=None, attribute=None):
-        svc = self.get_object()
-        att = ServiceAttribute.objects.get(pk=attribute)
-        ser = ServicettributeSerializer(att, data=request.data)
-        ser.is_valid(raise_exception = True)
-        att.name = ser.validated_data.get("name", att.name)
-        att.value = ser.validated_data.get("value", att.value)
-        att.save()
-        return Response(ServiceAttributeSerializer(att).data)
-
-    def delete_attribute(self, request, pk=None, attribute=None):
-        att = ServiceAttribute.objects.get(pk=attribute)
-        att.delete()
-        return Response(status=status.HTTP_204_NO_CONTENT)
-
-
-
-
-
-
diff --git a/xos/api/tenant/onos/app.py b/xos/api/tenant/onos/app.py
deleted file mode 100644
index a93fa0d..0000000
--- a/xos/api/tenant/onos/app.py
+++ /dev/null
@@ -1,106 +0,0 @@
-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.onos.models import ONOSService, ONOSApp
-from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
-from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
-
-def get_default_onos_service():
-    onos_services = ONOSService.objects.all()
-    if onos_services:
-        return onos_services[0].id
-    return None
-
-class ONOSAppSerializer(PlusModelSerializer):
-    id = ReadOnlyField()
-    name = serializers.CharField()
-    dependencies = serializers.CharField()
-
-    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
-    class Meta:
-        model = ONOSApp
-        fields = ('humanReadableName', 'id', 'name', 'dependencies')
-
-    def getHumanReadableName(self, obj):
-        return obj.__unicode__()
-
-class TenantAttributeSerializer(serializers.Serializer):
-    id = ReadOnlyField()
-    name = serializers.CharField(required=False)
-    value = serializers.CharField(required=False)
-
-class ONOSAppViewSet(XOSViewSet):
-    base_name = "app"
-    method_name = "app"
-    method_kind = "viewset"
-    serializer_class = ONOSAppSerializer
-
-    custom_serializers = {"set_attribute": TenantAttributeSerializer}
-
-    @classmethod
-    def get_urlpatterns(self, api_path="^"):
-        patterns = super(ONOSAppViewSet, self).get_urlpatterns(api_path=api_path)
-
-        patterns.append( self.detail_url("attributes/$", {"get": "get_attributes", "post": "add_attribute"}, "attributes") )
-        patterns.append( self.detail_url("attributes/(?P<attribute>[0-9]+)/$", {"get": "get_attribute", "put": "set_attribute", "delete": "delete_attribute"}, "attribute") )
-
-        return patterns
-
-    def get_queryset(self):
-        queryset = ONOSApp.objects.all()
-
-        # Since name isn't a real database field of the Tenant object, we have
-        # to go through some extra work...
-        name = self.request.query_params.get('name', None)
-        if name is not None:
-            ids = [x.id for x in queryset.all() if x.name == name]
-            return queryset.filter(id__in=ids)
-
-        return queryset
-
-    def get_attributes(self, request, pk=None):
-        app = self.get_object()
-        qs = app.tenantattributes.all()
-        name = self.request.query_params.get('attribute_name', None)
-        if name is not None:
-            qs = qs.filter(name=name)
-        return Response(TenantAttributeSerializer(qs, many=True).data)
-
-    def add_attribute(self, request, pk=None):
-        app = self.get_object()
-        ser = TenantAttributeSerializer(data=request.data)
-        ser.is_valid(raise_exception = True)
-        att = TenantAttribute(tenant=app, **ser.validated_data)
-        att.save()
-        return Response(TenantAttributeSerializer(att).data)
-
-    def get_attribute(self, request, pk=None, attribute=None):
-        app = self.get_object()
-        att = TenantAttribute.objects.get(pk=attribute)
-        return Response(TenantAttributeSerializer(att).data)
-
-    def set_attribute(self, request, pk=None, attribute=None):
-        app = self.get_object()
-        att = TenantAttribute.objects.get(pk=attribute)
-        ser = TenantAttributeSerializer(att, data=request.data)
-        ser.is_valid(raise_exception = True)
-        att.name = ser.validated_data.get("name", att.name)
-        att.value = ser.validated_data.get("value", att.value)
-        att.save()
-        return Response(TenantAttributeSerializer(att).data)
-
-    def delete_attribute(self, request, pk=None, attribute=None):
-        att = TenantAttribute.objects.get(pk=attribute)
-        att.delete()
-        return Response(status=status.HTTP_204_NO_CONTENT)
-
-
-
-
-
-
diff --git a/xos/attic/header.py b/xos/attic/header.py
index 33498dd..e3ab236 100644
--- a/xos/attic/header.py
+++ b/xos/attic/header.py
@@ -1,5 +1,5 @@
 from django.db import models
-from core.models import Service, XOSBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor
+from core.models import Service, XOSBase, Slice, Instance, ServiceInstance, Node, Image, User, Flavor
 from core.models.xosbase import StrippedCharField
 import os
 from django.db import models, transaction
diff --git a/xos/attic/onosapp_model.py b/xos/attic/onosapp_model.py
index a294f2d..8ac7d9e 100644
--- a/xos/attic/onosapp_model.py
+++ b/xos/attic/onosapp_model.py
@@ -1,17 +1,6 @@
 def __init__(self, *args, **kwargs):
     onos_services = ONOSService.objects.all()
     if onos_services:
-        self._meta.get_field("provider_service").default = onos_services[0].id
+        self._meta.get_field("owner").default = onos_services[0].id
     super(ONOSApp, self).__init__(*args, **kwargs)
 
-def save(self, *args, **kwargs):
-    if not self.creator:
-        if not getattr(self, "caller", None):
-            # caller must be set when creating a vCPE since it creates a slice
-            raise XOSProgrammingError("ONOSApp's self.caller was not set")
-        self.creator = self.caller
-        if not self.creator:
-            raise XOSProgrammingError("ONOSApp's self.creator was not set")
-
-    super(ONOSApp, self).save(*args, **kwargs)
-
diff --git a/xos/header.py b/xos/header.py
index 33498dd..e3ab236 100755
--- a/xos/header.py
+++ b/xos/header.py
@@ -1,5 +1,5 @@
 from django.db import models
-from core.models import Service, XOSBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor
+from core.models import Service, XOSBase, Slice, Instance, ServiceInstance, Node, Image, User, Flavor
 from core.models.xosbase import StrippedCharField
 import os
 from django.db import models, transaction
diff --git a/xos/onos-onboard.yaml b/xos/onos-onboard.yaml
index 6f59f10..2670375 100644
--- a/xos/onos-onboard.yaml
+++ b/xos/onos-onboard.yaml
@@ -18,8 +18,6 @@
           admin_template: templates/onosadmin.html
           #tosca_custom_types: exampleservice.yaml
           tosca_resource: tosca/resources/onosservice.py, tosca/resources/onosapp.py
-          rest_service: api/service/onos.py
-          rest_tenant: subdirectory:onos api/tenant/onos/app.py
           private_key: file:///opt/xos/key_import/onos_rsa
           public_key: file:///opt/xos/key_import/onos_rsa.pub
 
diff --git a/xos/onos.xproto b/xos/onos.xproto
index 24345ea..2481a5a 100644
--- a/xos/onos.xproto
+++ b/xos/onos.xproto
@@ -2,13 +2,11 @@
 option name="onos";
 option verbose_name="ONOS Service";
 
-message ONOSApp (Tenant){
+message ONOSApp (ServiceInstance){
      optional string install_dependencies = 1 [db_index = False, null = True, blank = True];
      optional string dependencies = 2 [db_index = False, null = True, blank = True];
-     optional manytoone creator->User:onos_apps = 3 [db_index = True, null = True, blank = True];
 }
 
-
 message ONOSService (Service){
      optional string rest_hostname = 1 [db_index = False, max_length = 255, null = True, content_type = "stripped", blank = True];
      required int32 rest_port = 2 [default = 8181, null = False, db_index = False, blank = False];
diff --git a/xos/synchronizer/steps/sync_onosapp.py b/xos/synchronizer/steps/sync_onosapp.py
index ae9c5d7..e26cc1e 100644
--- a/xos/synchronizer/steps/sync_onosapp.py
+++ b/xos/synchronizer/steps/sync_onosapp.py
@@ -42,10 +42,10 @@
         return None
 
     def get_onos_service(self, o):
-        if not o.provider_service:
+        if not o.owner:
             return None
 
-        onoses = ONOSService.objects.filter(id=o.provider_service.id)
+        onoses = ONOSService.objects.filter(id=o.owner.id)
         if not onoses:
             return None
 
@@ -115,7 +115,7 @@
 
         # Combine the service attributes with the tenant attributes. Tenant
         # attribute can override service attributes.
-        attrs = o.provider_service.serviceattribute_dict
+        attrs = o.owner.serviceattribute_dict
         attrs.update(o.tenantattribute_dict)
 
         ordered_attrs = attrs.keys()
diff --git a/xos/tosca/resources/onosapp.py b/xos/tosca/resources/onosapp.py
index 39b3a2b..005e345 100644
--- a/xos/tosca/resources/onosapp.py
+++ b/xos/tosca/resources/onosapp.py
@@ -1,5 +1,5 @@
 from xosresource import XOSResource
-from core.models import User, TenantAttribute, Service
+from core.models import User, ServiceInstanceAttribute, Service, ServiceInstanceLink
 from services.onos.models import ONOSApp, ONOSService
 
 class XOSONOSApp(XOSResource):
@@ -13,24 +13,14 @@
         # provider_service is mandatory and must be the ONOS Service
         provider_name = self.get_requirement("tosca.relationships.TenantOfService", throw_exception=throw_exception)
         if provider_name:
-            args["provider_service"] = self.get_xos_object(ONOSService, throw_exception=throw_exception, name=provider_name)
-
-        # subscriber_service is optional and can be any service
-        subscriber_name = self.get_requirement("tosca.relationships.UsedByService", throw_exception=False)
-        if subscriber_name:
-            args["subscriber_service"] = self.get_xos_object(Service, throw_exception=throw_exception, name=subscriber_name)
+            args["owner"] = self.get_xos_object(ONOSService, throw_exception=throw_exception, name=provider_name)
 
         return args
 
-    def get_existing_objs(self):
-        objs = ONOSApp.objects.all()
-        objs = [x for x in objs if x.name == self.obj_name]
-        return objs
-
     def set_tenant_attr(self, obj, prop_name, value):
         value = self.try_intrinsic_function(value)
         if value:
-            attrs = TenantAttribute.objects.filter(tenant=obj, name=prop_name)
+            attrs = ServiceInstanceAttribute.objects.filter(service_instance=obj, name=prop_name)
             if attrs:
                 attr = attrs[0]
                 if attr.value != value:
@@ -39,7 +29,7 @@
                     attr.save()
             else:
                 self.info("adding attribute %s" % prop_name)
-                ta = TenantAttribute(tenant=obj, name=prop_name, value=value)
+                ta = ServiceInstanceAttribute(service_instance=obj, name=prop_name, value=value)
                 ta.save()
 
     def postprocess(self, obj):
@@ -55,5 +45,14 @@
             elif k == "autogenerate":
                 self.set_tenant_attr(obj, k, v)
 
+        # subscriber_service is optional and can be any service
+        subscriber_name = self.get_requirement("tosca.relationships.UsedByService", throw_exception=False)
+        if subscriber_name:
+            sub_serv = self.get_xos_object(Service, throw_exception=True, name=subscriber_name)
+            existing_links = ServiceInstanceLink.objects.filter(provider_service_instance_id = obj.id, subscriber_service_id = sub_serv.id)
+            if not existing_links:
+                link = ServiceInstanceLink(provider_service_instance = obj, subscriber_service = sub_serv)
+                link.save()
+
     def can_delete(self, obj):
         return super(XOSONOSApp, self).can_delete(obj)