CORD-1520 Update to new Service/Tenancy models

Change-Id: I54a60c9af962aa6fa9216b2d844b03e529a8b984
diff --git a/xos/admin.py b/xos/admin.py
index 71003c4..6432f9f 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
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, SubscriberLinkInline, ProviderLinkInline, ProviderDependencyInline,SubscriberDependencyInline
 from core.middleware import get_request
 
 from functools import update_wrapper
@@ -31,7 +31,7 @@
                  ("vSG config", {'fields': ["dns_servers", "docker_image_name", "docker_insecure_registry"],
                                      'classes':['suit-tab suit-tab-vsg']}) ]
     readonly_fields = ('backend_status_text', "service_specific_attribute")
-    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline, ProviderDependencyInline,SubscriberDependencyInline]
 
     extracontext_registered_admins = True
 
@@ -44,6 +44,7 @@
         #('tools', 'Tools'),
         ('slices','Slices'),
         ('serviceattrs','Additional Attributes'),
+        ('servicetenants', 'Dependencies'),
         ('serviceprivileges','Privileges') ,
     )
 
@@ -60,8 +61,7 @@
 
     def __init__(self,*args,**kwargs):
         super (VSGTenantForm,self ).__init__(*args,**kwargs)
-        self.fields['kind'].widget.attrs['readonly'] = True
-        self.fields['provider_service'].queryset = VSGService.objects.all()
+        self.fields['owner'].queryset = VSGService.objects.all()
         if self.instance:
             # fields for the attributes
             self.fields['last_ansible_hash'].initial = self.instance.last_ansible_hash
@@ -69,10 +69,9 @@
             self.fields['wan_container_mac'].initial = self.instance.wan_container_mac
         if (not self.instance) or (not self.instance.pk):
             # default fields for an 'add' form
-            self.fields['kind'].initial = VCPE_KIND
             self.fields['creator'].initial = get_request().user
             if VSGService.objects.exists():
-               self.fields["provider_service"].initial = VSGService.objects.all()[0]
+               self.fields["owner"].initial = VSGService.objects.all()[0]
 
     def save(self, commit=True):
         self.instance.creator = self.cleaned_data.get("creator")
@@ -85,15 +84,17 @@
         fields = '__all__'
 
 class VSGTenantAdmin(ReadOnlyAwareAdmin):
-    list_display = ('backend_status_icon', 'id', 'subscriber_tenant' )
+    list_display = ('backend_status_icon', 'id', )
     list_display_links = ('backend_status_icon', 'id')
-    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'service_specific_id',
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'owner', 'service_specific_id',
                                      'wan_container_ip', 'wan_container_mac', 'creator', 'instance', 'last_ansible_hash'],
                           'classes':['suit-tab suit-tab-general']})]
     readonly_fields = ('backend_status_text', 'service_specific_attribute', 'wan_container_ip', 'wan_container_mac')
+    inlines = (ProviderLinkInline, SubscriberLinkInline)
     form = VSGTenantForm
 
-    suit_form_tabs = (('general','Details'),)
+    suit_form_tabs = (('general','Details'),
+                      ('servicelinks','Links'),)
 
     def get_queryset(self, request):
         return VSGTenant.select_by_user(request.user)
diff --git a/xos/api/service/vsg/vsgservice.py b/xos/api/service/vsg/vsgservice.py
deleted file mode 100644
index 5fe04f2..0000000
--- a/xos/api/service/vsg/vsgservice.py
+++ /dev/null
@@ -1,78 +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 viewsets
-from rest_framework import status
-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.vsg.models import VSGService
-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
-from django.views.decorators.csrf import ensure_csrf_cookie
-
-class VSGServiceForApi(VSGService):
-    class Meta:
-        proxy = True
-        app_label = "cord"
-
-    def __init__(self, *args, **kwargs):
-        super(VSGServiceForApi, self).__init__(*args, **kwargs)
-
-    def save(self, *args, **kwargs):
-        super(VSGServiceForApi, self).save(*args, **kwargs)
-
-    def __init__(self, *args, **kwargs):
-        super(VSGService, self).__init__(*args, **kwargs)
-
-class VSGServiceSerializer(PlusModelSerializer):
-        id = ReadOnlyField()
-        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
-        wan_container_gateway_ip = serializers.CharField(required=False)
-        wan_container_gateway_mac = serializers.CharField(required=False)
-        dns_servers = serializers.CharField(required=False)
-        url_filter_kind = serializers.CharField(required=False)
-        node_label = serializers.CharField(required=False)
-
-        class Meta:
-            model = VSGServiceForApi
-            fields = ('humanReadableName',
-                      'id',
-                      'wan_container_gateway_ip',
-                      'wan_container_gateway_mac',
-                      'dns_servers',
-                      'url_filter_kind',
-                      'node_label')
-
-        def getHumanReadableName(self, obj):
-            return obj.__unicode__()
-
-# @ensure_csrf_cookie
-class VSGServiceViewSet(XOSViewSet):
-    base_name = "vsgservice"
-    method_name = None # use the api endpoint /api/service/vsg/
-    method_kind = "viewset"
-    queryset = VSGService.objects.select_related().all()
-    serializer_class = VSGServiceSerializer
-
-    @classmethod
-    def get_urlpatterns(self, api_path="^"):
-        patterns = super(VSGServiceViewSet, self).get_urlpatterns(api_path=api_path)
-
-        return patterns
-
-    def list(self, request):
-        object_list = self.filter_queryset(self.get_queryset())
-
-        serializer = self.get_serializer(object_list, many=True)
-
-        return Response(serializer.data)
-
diff --git a/xos/api/tenant/cord/vsg.py b/xos/api/tenant/cord/vsg.py
deleted file mode 100644
index 2058942..0000000
--- a/xos/api/tenant/cord/vsg.py
+++ /dev/null
@@ -1,62 +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.vsg.models import VSGTenant, VSGService
-from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
-from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
-
-def get_default_vsg_service():
-    vsg_services = VSGService.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.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/attic/header.py b/xos/attic/header.py
index 802b6b9..ff8a596 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, NetworkParameter, NetworkParameterType, Port, AddressPool, User
+from core.models import Service, XOSBase, Slice, Instance, TenantWithContainer, Node, Image, User, Flavor, NetworkParameter, NetworkParameterType, Port, AddressPool, User
 from core.models.xosbase import StrippedCharField
 import os
 from django.db import models, transaction
diff --git a/xos/header.py b/xos/header.py
deleted file mode 100755
index db6f030..0000000
--- a/xos/header.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from django.db import models
-from core.models import Service, XOSBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, NetworkParameter, NetworkParameterType, Port, AddressPool, User
-from core.models.xosbase import StrippedCharField
-import os
-from django.db import models, transaction
-from django.forms.models import model_to_dict
-from django.db.models import *
-from operator import itemgetter, attrgetter, methodcaller
-from core.models import Tag
-from core.models.service import LeastLoadedNodeScheduler
-from services.vrouter.models import VRouterService, VRouterTenant
-import traceback
-from xos.exceptions import *
-
-class ConfigurationError(Exception):
-    pass
-
-VCPE_KIND = "vCPE"
-CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
-
diff --git a/xos/header.py b/xos/header.py
new file mode 120000
index 0000000..721b5c0
--- /dev/null
+++ b/xos/header.py
@@ -0,0 +1 @@
+attic/header.py
\ No newline at end of file
diff --git a/xos/synchronizer/model_policies/model_policy_vsgtenant.py b/xos/synchronizer/model_policies/model_policy_vsgtenant.py
index cf7be71..8674446 100644
--- a/xos/synchronizer/model_policies/model_policy_vsgtenant.py
+++ b/xos/synchronizer/model_policies/model_policy_vsgtenant.py
@@ -28,13 +28,17 @@
     def cleanup_orphans(self, tenant):
         # ensure vSG only has one vRouter
         cur_vrouter = tenant.vrouter
-        for vrouter in list(VRouterTenant.objects.filter(subscriber_tenant_id=tenant.id)):  # TODO: Hardcoded dependency
-            if (not cur_vrouter) or (vrouter.id != cur_vrouter.id):
-                # print "XXX clean up orphaned vrouter", vrouter
-                vrouter.delete()
+        for link in tenant.subscribed_links.all():
+            # TODO: hardcoded dependency
+            # cast from ServiceInstance to VRouterTenant
+            vrouters = VRouterTenant.objects.filter(id = link.provider_service_instance.id)
+            for vrouter in vrouters:
+                if (not cur_vrouter) or (vrouter.id != cur_vrouter.id):
+                    # print "XXX clean up orphaned vrouter", vrouter
+                    vrouter.delete()
 
     def get_vsg_service(self, tenant):
-        return VSGService.objects.get(id=tenant.provider_service.id)
+        return VSGService.objects.get(id=tenant.owner.id)
 
     def find_instance_for_s_tag(self, s_tag):
         tags = Tag.objects.filter(name="s_tag", value=s_tag)
@@ -57,7 +61,7 @@
         if not flavors:
             raise SynchronizerConfigurationError("No m1.small flavor")
 
-        slice = tenant.provider_service.slices.first()
+        slice = tenant.owner.slices.first()
 
         (node, parent) = LeastLoadedNodeScheduler(slice, label=self.get_vsg_service(tenant).node_label).pick()
 
@@ -107,7 +111,7 @@
         return port
 
     def get_lan_network(self, tenant, instance):
-        slice = tenant.provider_service.slices.all()[0]
+        slice = tenant.owner.slices.all()[0]
         # there should only be one network private network, and its template should not be the management template
         lan_networks = [x for x in slice.networks.all() if
                         x.template.visibility == "private" and (not "management" in x.template.name)]
@@ -150,7 +154,7 @@
             if tenant.volt and tenant.volt.s_tag:
                 tags = Tag.objects.filter(name="s_tag", value=tenant.volt.s_tag)
                 if not tags:
-                    tag = Tag(service=tenant.provider_service, content_type=instance.self_content_type_id, object_id=instance.id, name="s_tag", value=str(tenant.volt.s_tag))
+                    tag = Tag(service=tenant.owner, content_type=instance.self_content_type_id, object_id=instance.id, name="s_tag", value=str(tenant.volt.s_tag))
                     tag.save()
 
             # VTN-CORD needs a WAN address for the VM, so that the VM can
@@ -158,11 +162,11 @@
             tags = Tag.objects.filter(content_type=instance.self_content_type_id, object_id=instance.id, name="vm_vrouter_tenant")
             if not tags:
                 vrouter = self.allocate_public_service_instance(address_pool_name="addresses_vsg",
-                                                                subscriber_service=tenant.provider_service)
+                                                                subscriber_service=tenant.owner)
                 vrouter.set_attribute("tenant_for_instance_id", instance.id)
                 vrouter.save()
                 # TODO: potential partial failure
-                tag = Tag(service=tenant.provider_service, content_type=instance.self_content_type_id, object_id=instance.id, name="vm_vrouter_tenant", value="%d" % vrouter.id)
+                tag = Tag(service=tenant.owner, content_type=instance.self_content_type_id, object_id=instance.id, name="vm_vrouter_tenant", value="%d" % vrouter.id)
                 tag.save()
 
             instance.no_sync = False   # allow the synchronizer to run now
diff --git a/xos/synchronizer/steps/sync_vcpetenant.py b/xos/synchronizer/steps/sync_vcpetenant.py
index d3b0f11..79aca2c 100644
--- a/xos/synchronizer/steps/sync_vcpetenant.py
+++ b/xos/synchronizer/steps/sync_vcpetenant.py
@@ -29,10 +29,10 @@
         super(SyncVSGTenant, self).__init__(*args, **kwargs)
 
     def get_vcpe_service(self, o):
-        if not o.provider_service:
+        if not o.owner:
             return None
 
-        vcpes = VSGService.objects.filter(id=o.provider_service.id)
+        vcpes = VSGService.objects.filter(id=o.owner.id)
         if not vcpes:
             return None
 
@@ -147,7 +147,7 @@
 
         objs = VSGTenant.objects.all()
         for obj in objs:
-            if obj.provider_service.id != monitoring_agent_info.service.id:
+            if obj.owner.id != monitoring_agent_info.service.id:
                 logger.info("handle watch notifications for service monitoring agent info...ignoring because service attribute in monitoring agent info:%s is not matching" % (monitoring_agent_info))
                 return
 
diff --git a/xos/vsg-onboard.yaml b/xos/vsg-onboard.yaml
index 0c2f7a0..0b03225 100644
--- a/xos/vsg-onboard.yaml
+++ b/xos/vsg-onboard.yaml
@@ -18,8 +18,6 @@
           admin_template: templates/vcpeadmin.html
           #tosca_custom_types: exampleservice.yaml
           tosca_resource: tosca/resources/vcpeservice.py
-          rest_service: subdirectory:vsg api/service/vsg/vsgservice.py
-          rest_tenant: subdirectory:cord api/tenant/cord/vsg.py
           private_key: file:///opt/xos/key_import/vsg_rsa
           public_key: file:///opt/xos/key_import/vsg_rsa.pub