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