CORD-1250 Update to new Service/Tenancy models
Change-Id: I2e5fa0dd7d62a6451a6726eeaba2c3aaf1b83bc9
diff --git a/xos/admin.py b/xos/admin.py
index 78e00fd..15fe786 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
@@ -30,7 +30,7 @@
list_display_links = ('backend_status_icon', 'name', )
fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url" ], '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
@@ -41,6 +41,7 @@
#('tools', 'Tools'),
('slices','Slices'),
('serviceattrs','Additional Attributes'),
+ ('servicetenants', 'Dependencies'),
('serviceprivileges','Privileges'),
)
@@ -54,8 +55,7 @@
def __init__(self,*args,**kwargs):
super (VOLTTenantForm,self ).__init__(*args,**kwargs)
- self.fields['kind'].widget.attrs['readonly'] = True
- self.fields['provider_service'].queryset = VOLTService.objects.all()
+ self.fields['owner'].queryset = VOLTService.objects.all()
if self.instance:
# fields for the attributes
self.fields['c_tag'].initial = self.instance.c_tag
@@ -63,10 +63,9 @@
self.fields['creator'].initial = self.instance.creator
if (not self.instance) or (not self.instance.pk):
# default fields for an 'add' form
- self.fields['kind'].initial = VOLT_KIND
self.fields['creator'].initial = get_request().user
if VOLTService.objects.exists():
- self.fields["provider_service"].initial = VOLTService.objects.all()[0]
+ self.fields["owner"].initial = VOLTService.objects.all()[0]
def save(self, commit=True):
self.instance.s_tag = self.cleaned_data.get("s_tag")
@@ -80,15 +79,16 @@
class VOLTTenantAdmin(ReadOnlyAwareAdmin):
- list_display = ('backend_status_icon', 'id', 'service_specific_id', 's_tag', 'c_tag', 'subscriber_root' )
+ list_display = ('backend_status_icon', 'id', 'service_specific_id', 's_tag', 'c_tag', )
list_display_links = ('backend_status_icon', 'id')
- fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_root', 'service_specific_id', # 'service_specific_attribute',
+ fieldsets = [ (None, {'fields': ['backend_status_text', 'owner', 'service_specific_id', # 'service_specific_attribute',
's_tag', 'c_tag', 'creator'],
'classes':['suit-tab suit-tab-general']})]
readonly_fields = ('backend_status_text', 'service_specific_attribute')
+ inlines = (ProviderLinkInline, SubscriberLinkInline)
form = VOLTTenantForm
- suit_form_tabs = (('general','Details'),)
+ suit_form_tabs = (('general','Details'), ('servicelinks','Links'),)
def get_queryset(self, request):
return VOLTTenant.select_by_user(request.user)
diff --git a/xos/api/tenant/cord/subscriber.py b/xos/api/tenant/cord/subscriber.py
deleted file mode 100644
index 036e4cc..0000000
--- a/xos/api/tenant/cord/subscriber.py
+++ /dev/null
@@ -1,385 +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.volt.models import VOLTTenant
-from services.rcord.models import CordSubscriberRoot
-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 CordSubscriberNew(CordSubscriberRoot):
- class Meta:
- proxy = True
- app_label = "cord"
-
- def __init__(self, *args, **kwargs):
- super(CordSubscriberNew, self).__init__(*args, **kwargs)
-
- def __unicode__(self):
- return u"cordSubscriber-%s" % str(self.id)
-
- @property
- def features(self):
- return {"cdn": self.cdn_enable,
- "uplink_speed": self.uplink_speed,
- "downlink_speed": self.downlink_speed,
- "uverse": self.enable_uverse,
- "status": self.status}
-
- @features.setter
- def features(self, value):
- self.cdn_enable = value.get("cdn", self.get_default_attribute("cdn_enable"))
- self.uplink_speed = value.get("uplink_speed", self.get_default_attribute("uplink_speed"))
- self.downlink_speed = value.get("downlink_speed", self.get_default_attribute("downlink_speed"))
- self.enable_uverse = value.get("uverse", self.get_default_attribute("enable_uverse"))
- self.status = value.get("status", self.get_default_attribute("status"))
-
-
- def update_features(self, value):
- d=self.features
- d.update(value)
- self.features = d
-
- @property
- def identity(self):
- return {"account_num": self.service_specific_id,
- "name": self.name}
-
- @identity.setter
- def identity(self, value):
- self.service_specific_id = value.get("account_num", self.service_specific_id)
- self.name = value.get("name", self.name)
-
- def update_identity(self, value):
- d=self.identity
- d.update(value)
- self.identity = d
-
- @property
- def related(self):
- related = {}
- if self.volt:
- related["volt_id"] = self.volt.id
- related["s_tag"] = self.volt.s_tag
- related["c_tag"] = self.volt.c_tag
- if self.volt.vcpe:
- related["vsg_id"] = self.volt.vcpe.id
- if self.volt.vcpe.instance:
- related["instance_id"] = self.volt.vcpe.instance.id
- related["instance_name"] = self.volt.vcpe.instance.name
- related["wan_container_ip"] = self.volt.vcpe.wan_container_ip
- if self.volt.vcpe.instance.node:
- related["compute_node_name"] = self.volt.vcpe.instance.node.name
- return related
-
- def save(self, *args, **kwargs):
- super(CordSubscriberNew, self).save(*args, **kwargs)
-
-class CordDevice(object):
- def __init__(self, d={}, subscriber=None):
- self.d = d
- self.subscriber = subscriber
-
- @property
- def mac(self):
- return self.d.get("mac", None)
-
- @mac.setter
- def mac(self, value):
- self.d["mac"] = value
-
- @property
- def identity(self):
- return {"name": self.d.get("name", None)}
-
- @identity.setter
- def identity(self, value):
- self.d["name"] = value.get("name", None)
-
- @property
- def features(self):
- return {"uplink_speed": self.d.get("uplink_speed", None),
- "downlink_speed": self.d.get("downlink_speed", None)}
-
- @features.setter
- def features(self, value):
- self.d["uplink_speed"] = value.get("uplink_speed", None)
- self.d["downlink_speed"] = value.get("downlink_speed", None)
-
- def update_features(self, value):
- d=self.features
- d.update(value)
- self.features = d
-
- def update_identity(self, value):
- d=self.identity
- d.update(value)
- self.identity = d
-
- def save(self):
- if self.subscriber:
- dev=self.subscriber.find_device(self.mac)
- if dev:
- self.subscriber.update_device(**self.d)
- else:
- self.subscriber.create_device(**self.d)
-
-# Add some structure to the REST API by subdividing the object into
-# features, identity, and related.
-
-class FeatureSerializer(serializers.Serializer):
- cdn = serializers.BooleanField(required=False)
- uplink_speed = serializers.IntegerField(required=False)
- downlink_speed = serializers.IntegerField(required=False)
- uverse = serializers.BooleanField(required=False)
- status = serializers.CharField(required=False)
-
-class IdentitySerializer(serializers.Serializer):
- account_num = serializers.CharField(required=False)
- name = serializers.CharField(required=False)
-
-class DeviceFeatureSerializer(serializers.Serializer):
- uplink_speed = serializers.IntegerField(required=False)
- downlink_speed = serializers.IntegerField(required=False)
-
-class DeviceIdentitySerializer(serializers.Serializer):
- name = serializers.CharField(required=False)
-
-class DeviceSerializer(serializers.Serializer):
- mac = serializers.CharField(required=True)
- identity = DeviceIdentitySerializer(required=False)
- features = DeviceFeatureSerializer(required=False)
-
- class Meta:
- fields = ('mac', 'identity', 'features')
-
-class CordSubscriberSerializer(PlusModelSerializer):
- id = ReadOnlyField()
- humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
- features = FeatureSerializer(required=False)
- identity = IdentitySerializer(required=False)
- related = serializers.DictField(required=False)
-
- nested_fields = ["features", "identity"]
-
- class Meta:
- model = CordSubscriberNew
- fields = ('humanReadableName',
- 'id',
- 'features',
- 'identity',
- 'related')
-
- def getHumanReadableName(self, obj):
- return obj.__unicode__()
-
-# @ensure_csrf_cookie
-class CordSubscriberViewSet(XOSViewSet):
- base_name = "subscriber"
- method_name = "subscriber"
- method_kind = "viewset"
- queryset = CordSubscriberNew.objects.select_related().all()
- serializer_class = CordSubscriberSerializer
-
- custom_serializers = {"set_features": FeatureSerializer,
- "set_feature": FeatureSerializer,
- "set_identities": IdentitySerializer,
- "set_identity": IdentitySerializer,
- "get_devices": DeviceSerializer,
- "add_device": DeviceSerializer,
- "get_device_feature": DeviceFeatureSerializer,
- "set_device_feature": DeviceFeatureSerializer}
-
- @classmethod
- def get_urlpatterns(self, api_path="^"):
- patterns = super(CordSubscriberViewSet, self).get_urlpatterns(api_path=api_path)
- patterns.append( self.detail_url("features/$", {"get": "get_features", "put": "set_features"}, "features") )
- patterns.append( self.detail_url("features/(?P<feature>[a-zA-Z0-9\-_]+)/$", {"get": "get_feature", "put": "set_feature"}, "get_feature") )
- patterns.append( self.detail_url("identity/$", {"get": "get_identities", "put": "set_identities"}, "identities") )
- patterns.append( self.detail_url("identity/(?P<identity>[a-zA-Z0-9\-_]+)/$", {"get": "get_identity", "put": "set_identity"}, "get_identity") )
-
- patterns.append( self.detail_url("devices/$", {"get": "get_devices", "post": "add_device"}, "devicees") )
- patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/$", {"get": "get_device", "delete": "delete_device"}, "getset_device") )
- patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/features/(?P<feature>[a-zA-Z0-9\-_]+)/$", {"get": "get_device_feature", "put": "set_device_feature"}, "getset_device_feature") )
- patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/identity/(?P<identity>[a-zA-Z0-9\-_]+)/$", {"get": "get_device_identity", "put": "set_device_identity"}, "getset_device_identity") )
-
- patterns.append( url(self.api_path + "account_num_lookup/(?P<account_num>[0-9\-]+)/$", self.as_view({"get": "account_num_detail"}), name="account_num_detail") )
-
- patterns.append( url(self.api_path + "ssidmap/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") )
- patterns.append( url(self.api_path + "ssidmap/$", self.as_view({"get": "ssidlist"}), name="ssidlist") )
-
- 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)
-
- def get_features(self, request, pk=None):
- subscriber = self.get_object()
- return Response(FeatureSerializer(subscriber.features).data)
-
- def set_features(self, request, pk=None):
- subscriber = self.get_object()
- ser = FeatureSerializer(subscriber.features, data=request.data)
- ser.is_valid(raise_exception = True)
- subscriber.update_features(ser.validated_data)
- subscriber.save()
- return Response(FeatureSerializer(subscriber.features).data)
-
- def get_feature(self, request, pk=None, feature=None):
- subscriber = self.get_object()
- return Response({feature: FeatureSerializer(subscriber.features).data[feature]})
-
- def set_feature(self, request, pk=None, feature=None):
- subscriber = self.get_object()
- if [feature] != request.data.keys():
- raise serializers.ValidationError("feature %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
- ser = FeatureSerializer(subscriber.features, data=request.data)
- ser.is_valid(raise_exception = True)
- subscriber.update_features(ser.validated_data)
- subscriber.save()
- return Response({feature: FeatureSerializer(subscriber.features).data[feature]})
-
- def get_identities(self, request, pk=None):
- subscriber = self.get_object()
- return Response(IdentitySerializer(subscriber.identity).data)
-
- def set_identities(self, request, pk=None):
- subscriber = self.get_object()
- ser = IdentitySerializer(subscriber.identity, data=request.data)
- ser.is_valid(raise_exception = True)
- subscriber.update_identity(ser.validated_data)
- subscriber.save()
- return Response(IdentitySerializer(subscriber.identity).data)
-
- def get_identity(self, request, pk=None, identity=None):
- subscriber = self.get_object()
- return Response({identity: IdentitySerializer(subscriber.identity).data[identity]})
-
- def set_identity(self, request, pk=None, identity=None):
- subscriber = self.get_object()
- if [identity] != request.data.keys():
- raise serializers.ValidationError("identity %s does not match keys in request body (%s)" % (identity, ",".join(request.data.keys())))
- ser = IdentitySerializer(subscriber.identity, data=request.data)
- ser.is_valid(raise_exception = True)
- subscriber.update_identity(ser.validated_data)
- subscriber.save()
- return Response({identity: IdentitySerializer(subscriber.identity).data[identity]})
-
- def get_devices(self, request, pk=None):
- subscriber = self.get_object()
- result = []
- for device in subscriber.devices:
- device = CordDevice(device, subscriber)
- result.append(DeviceSerializer(device).data)
- return Response(result)
-
- def add_device(self, request, pk=None):
- subscriber = self.get_object()
- ser = DeviceSerializer(subscriber.devices, data=request.data)
- ser.is_valid(raise_exception = True)
- newdevice = CordDevice(subscriber.create_device(**ser.validated_data), subscriber)
- subscriber.save()
- return Response(DeviceSerializer(newdevice).data)
-
- def get_device(self, request, pk=None, mac=None):
- subscriber = self.get_object()
- device = subscriber.find_device(mac)
- if not device:
- return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
- return Response(DeviceSerializer(CordDevice(device, subscriber)).data)
-
- def delete_device(self, request, pk=None, mac=None):
- subscriber = self.get_object()
- device = subscriber.find_device(mac)
- if not device:
- return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
- subscriber.delete_device(mac)
- subscriber.save()
- return Response("Okay")
-
- def get_device_feature(self, request, pk=None, mac=None, feature=None):
- subscriber = self.get_object()
- device = subscriber.find_device(mac)
- if not device:
- return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
- return Response({feature: DeviceFeatureSerializer(CordDevice(device, subscriber).features).data[feature]})
-
- def set_device_feature(self, request, pk=None, mac=None, feature=None):
- subscriber = self.get_object()
- device = subscriber.find_device(mac)
- if not device:
- return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
- if [feature] != request.data.keys():
- raise serializers.ValidationError("feature %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
- device = CordDevice(device, subscriber)
- ser = DeviceFeatureSerializer(device.features, data=request.data)
- ser.is_valid(raise_exception = True)
- device.update_features(ser.validated_data)
- device.save()
- subscriber.save()
- return Response({feature: DeviceFeatureSerializer(device.features).data[feature]})
-
- def get_device_identity(self, request, pk=None, mac=None, identity=None):
- subscriber = self.get_object()
- device = subscriber.find_device(mac)
- if not device:
- return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
- return Response({identity: DeviceIdentitySerializer(CordDevice(device, subscriber).identity).data[identity]})
-
- def set_device_identity(self, request, pk=None, mac=None, identity=None):
- subscriber = self.get_object()
- device = subscriber.find_device(mac)
- if not device:
- return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
- if [identity] != request.data.keys():
- raise serializers.ValidationError("identity %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
- device = CordDevice(device, subscriber)
- ser = DeviceIdentitySerializer(device.identity, data=request.data)
- ser.is_valid(raise_exception = True)
- device.update_identity(ser.validated_data)
- device.save()
- subscriber.save()
- return Response({identity: DeviceIdentitySerializer(device.identity).data[identity]})
-
- def account_num_detail(self, pk=None, account_num=None):
- object_list = CordSubscriberNew.objects.all()
- object_list = [x for x in object_list if x.service_specific_id == account_num]
- if not object_list:
- return Response("Failed to find account_num %s" % account_num, status=status.HTTP_404_NOT_FOUND)
-
- return Response( object_list[0].id )
-
- def ssidlist(self, request):
- object_list = CordSubscriberNew.objects.all()
-
- ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list ]
-
- return Response({"ssidmap": ssidmap})
-
- def ssiddetail(self, pk=None, ssid=None):
- object_list = CordSubscriberNew.objects.all()
-
- ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list if str(x.service_specific_id)==str(ssid) ]
-
- if len(ssidmap)==0:
- raise XOSNotFound("didn't find ssid %s" % str(ssid))
-
- return Response( ssidmap[0] )
-
diff --git a/xos/api/tenant/cord/volt.py b/xos/api/tenant/cord/volt.py
deleted file mode 100644
index 7da8e4f..0000000
--- a/xos/api/tenant/cord/volt.py
+++ /dev/null
@@ -1,97 +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.volt.models import VOLTTenant, VOLTService
-from services.rcord.models import CordSubscriberRoot
-from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
-from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
-
-def get_default_volt_service():
- volt_services = VOLTService.objects.all()
- if volt_services:
- return volt_services[0].id
- return None
-
-class VOLTTenantForAPI(VOLTTenant):
- class Meta:
- proxy = True
- app_label = "cord"
-
- @property
- def subscriber(self):
- return self.subscriber_root.id
-
- @subscriber.setter
- def subscriber(self, value):
- self.subscriber_root = value
-
- @property
- def related(self):
- related = {}
- if self.vcpe:
- related["vsg_id"] = self.vcpe.id
- if self.vcpe.instance:
- related["instance_id"] = self.vcpe.instance.id
- related["instance_name"] = self.vcpe.instance.name
- related["wan_container_ip"] = self.vcpe.wan_container_ip
- if self.vcpe.instance.node:
- related["compute_node_name"] = self.vcpe.instance.node.name
- return related
-
-class VOLTTenantSerializer(PlusModelSerializer):
- id = ReadOnlyField()
- service_specific_id = serializers.CharField(required=False)
- s_tag = serializers.CharField()
- c_tag = serializers.CharField()
- subscriber = serializers.PrimaryKeyRelatedField(queryset=CordSubscriberRoot.objects.all(), required=False)
- related = serializers.DictField(required=False)
-
- property_fields=["subscriber"]
-
- humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
- class Meta:
- model = VOLTTenantForAPI
- fields = ('humanReadableName', 'id', 'service_specific_id', 's_tag', 'c_tag', 'subscriber', 'related' )
-
- def getHumanReadableName(self, obj):
- return obj.__unicode__()
-
-class VOLTTenantViewSet(XOSViewSet):
- base_name = "volt"
- method_name = "volt"
- method_kind = "viewset"
- queryset = VOLTTenantForAPI.objects.all()
- serializer_class = VOLTTenantSerializer
-
- @classmethod
- def get_urlpatterns(self, api_path="^"):
- patterns = super(VOLTTenantViewSet, self).get_urlpatterns(api_path=api_path)
-
- return patterns
-
- def list(self, request):
- queryset = self.filter_queryset(self.get_queryset())
-
- c_tag = self.request.query_params.get('c_tag', None)
- if c_tag is not None:
- ids = [x.id for x in queryset if x.get_attribute("c_tag", None)==c_tag]
- queryset = queryset.filter(id__in=ids)
-
- s_tag = self.request.query_params.get('s_tag', None)
- if s_tag is not None:
- ids = [x.id for x in queryset if x.get_attribute("s_tag", None)==s_tag]
- queryset = queryset.filter(id__in=ids)
-
- serializer = self.get_serializer(queryset, many=True)
-
- return Response(serializer.data)
-
-
-
-
-
diff --git a/xos/attic/header.py b/xos/attic/header.py
index e76566e..1762be8 100644
--- a/xos/attic/header.py
+++ b/xos/attic/header.py
@@ -1,6 +1,6 @@
from django.db import models
from django.db.models import *
-from core.models import Service, XOSBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, TenantRoot, NetworkParameter, NetworkParameterType, Port, AddressPool, User
+from core.models import Service, XOSBase, Slice, Instance, ServiceInstance, ServiceInstanceLink, 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/attic/volttenant_model.py b/xos/attic/volttenant_model.py
index bf15c30..54a6ec3 100644
--- a/xos/attic/volttenant_model.py
+++ b/xos/attic/volttenant_model.py
@@ -1,24 +1,32 @@
def __init__(self, *args, **kwargs):
volt_services = VOLTService.objects.all()
if volt_services:
- self._meta.get_field("provider_service").default = volt_services[0].id
+ self._meta.get_field("owner").default = volt_services[0].id
super(VOLTTenant, self).__init__(*args, **kwargs)
self.cached_vcpe = None
@property
def vcpe(self):
+ # TODO: hardcoded service dependency
from services.vsg.models import VSGTenant
- vcpe = self.get_newest_subscribed_tenant(VSGTenant)
- if not vcpe:
+
+ vsg = None
+ for link in self.subscribed_links:
+ # cast from base class to derived class
+ vsgs = VSGTenant.objects.filter(serviceinstance_ptr=link.provider_service_instance)
+ if vsgs:
+ vsg = vsgs[0]
+
+ if not vsg:
return None
# always return the same object when possible
- if (self.cached_vcpe) and (self.cached_vcpe.id == vcpe.id):
+ if (self.cached_vcpe) and (self.cached_vcpe.id == vsg.id):
return self.cached_vcpe
- vcpe.caller = self.creator
- self.cached_vcpe = vcpe
- return vcpe
+ vsg.caller = self.creator
+ self.cached_vcpe = vsg
+ return vsg
@vcpe.setter
def vcpe(self, value):
@@ -26,23 +34,14 @@
@property
def subscriber(self):
- if not self.subscriber_root:
- return None
- subs = CordSubscriberRoot.objects.filter(id=self.subscriber_root.id)
- if not subs:
- return None
- return subs[0]
+ for link in self.provided_links:
+ # cast from base class to derived class
+ roots = CordSubscriberRoot.objects.filter(serviceinstance_ptr=link.subscriber_service_instance)
+ if roots:
+ return roots[0]
+ return None
def save(self, *args, **kwargs):
- # VOLTTenant probably doesn't need a SSID anymore; that will be handled
- # by CORDSubscriberRoot...
- # self.validate_unique_service_specific_id()
-
- if (self.subscriber_root is not None):
- subs = self.subscriber_root.get_subscribed_tenants(VOLTTenant)
- if (subs) and (self not in subs):
- raise XOSDuplicateKey("Subscriber should only be linked to one vOLT")
-
if not self.creator:
if not getattr(self, "caller", None):
# caller must be set when creating a vCPE since it creates a slice
@@ -52,5 +51,3 @@
raise XOSProgrammingError("VOLTTenant's self.creator was not set")
super(VOLTTenant, self).save(*args, **kwargs)
-
-
diff --git a/xos/synchronizer/model_policies/model_policy_volttenant.py b/xos/synchronizer/model_policies/model_policy_volttenant.py
index b474263..8d02091 100644
--- a/xos/synchronizer/model_policies/model_policy_volttenant.py
+++ b/xos/synchronizer/model_policies/model_policy_volttenant.py
@@ -39,36 +39,40 @@
self.logger.info("MODEL_POLICY: volttenant %s creating vsg" % tenant)
- vcpe = VSGTenant(provider_service=vsgServices[0],
- subscriber_tenant=tenant)
+ vcpe = VSGTenant(owner=vsgServices[0])
vcpe.creator = tenant.creator
vcpe.save()
+ link = ServiceInstanceLink(provider_service_instance = vcpe, subscriber_service_instance = tenant)
+ link.save()
def manage_subscriber(self, tenant):
- if (tenant.subscriber_root is None):
- # The vOLT is not connected to a Subscriber, so either find an
- # existing subscriber with the same SSID, or autogenerate a new
- # subscriber.
- #
- # TODO: This probably goes away when we rethink the ONOS-to-XOS
- # vOLT API.
+ # check for existing link to a root
+ links = tenant.provided_links.all()
+ for link in links:
+ roots = CordSubscriberRoot.objects.filter(id = link.subscriber_service_instance.id)
+ if roots:
+ return
- subs = CordSubscriberRoot.objects.filter(service_specific_id = tenant.service_specific_id)
- if subs:
- self.logger.info("MODEL_POLICY: volttenant %s using existing subscriber root" % tenant)
- sub = subs[0]
- else:
- self.logger.info("MODEL_POLICY: volttenant %s creating new subscriber root" % tenant)
- sub = CordSubscriberRoot(service_specific_id = tenant.service_specific_id,
- name = "autogenerated-for-vOLT-%s" % tenant.id)
- sub.save()
- tenant.subscriber_root = sub
- tenant.save()
+ subs = CordSubscriberRoot.objects.filter(service_specific_id = tenant.service_specific_id)
+ if subs:
+ self.logger.info("MODEL_POLICY: volttenant %s using existing subscriber root" % tenant)
+ sub = subs[0]
+ else:
+ self.logger.info("MODEL_POLICY: volttenant %s creating new subscriber root" % tenant)
+ sub = CordSubscriberRoot(service_specific_id = tenant.service_specific_id,
+ name = "autogenerated-for-vOLT-%s" % tenant.id)
+ sub.save()
+
+ link = ServiceInstanceLink(provider_service_instance = tenant, subscriber_service_instance = sub)
+ link.save()
def cleanup_orphans(self, tenant):
# ensure vOLT only has one vCPE
cur_vcpe = tenant.vcpe
- subscribed_vcpes = VSGTenant.objects.filter(subscriber_tenant_id = tenant.id)
- for vcpe in subscribed_vcpes:
- if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
- vcpe.delete()
+
+ links = tenant.subscribed_links.all()
+ for link in links:
+ vsgs = VSGTenant.objects.filter(id = link.provider_service_instance.id)
+ for vsg in vsgs:
+ if (not cur_vcpe) or (vsg.id != cur_vcpe.id):
+ vsg.delete()
diff --git a/xos/tosca/resources/CORDSubscriber.py b/xos/tosca/resources/CORDSubscriber.py
index a7c75c5..d91e5bb 100644
--- a/xos/tosca/resources/CORDSubscriber.py
+++ b/xos/tosca/resources/CORDSubscriber.py
@@ -1,4 +1,4 @@
-from core.models import User, TenantRootPrivilege, TenantRootRole
+#from core.models import User, TenantRootPrivilege, TenantRootRole
from services.rcord.models import CordSubscriberRoot
from xosresource import XOSResource
@@ -7,9 +7,9 @@
xos_model = CordSubscriberRoot
copyin_props = ["service_specific_id", "firewall_enable", "url_filter_enable", "cdn_enable", "url_filter_level"]
- def postprocess(self, obj):
- rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), ("tosca.relationships.AccessPrivilege", "access"), )
- self.postprocess_privileges(TenantRootRole, 'TenantRoot', rolemap, obj)
+# def postprocess(self, obj):
+# rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), ("tosca.relationships.AccessPrivilege", "access"), )
+# self.postprocess_privileges(TenantRootRole, TenantRootPrivilege, rolemap, obj, "tenant_root")
def can_delete(self, obj):
return super(XOSCORDSubscriber, self).can_delete(obj)
diff --git a/xos/tosca/resources/VOLTTenant.py b/xos/tosca/resources/VOLTTenant.py
index 82158a1..326cb92 100644
--- a/xos/tosca/resources/VOLTTenant.py
+++ b/xos/tosca/resources/VOLTTenant.py
@@ -1,4 +1,4 @@
-from core.models import User
+from core.models import User, ServiceInstanceLink
from services.volt.models import VOLTTenant, VOLTService, VOLT_KIND
from services.rcord.models import CordSubscriberRoot
@@ -15,26 +15,30 @@
provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
if provider_name:
- args["provider_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=provider_name)
-
- subscriber_name = self.get_requirement("tosca.relationships.BelongsToSubscriber")
- if subscriber_name:
- args["subscriber_root"] = self.get_xos_object(CordSubscriberRoot, throw_exception=throw_exception, name=subscriber_name)
+ args["owner"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=provider_name)
return args
def get_existing_objs(self):
args = self.get_xos_args(throw_exception=False)
- provider_service = args.get("provider_service", None)
+ provider_service = args.get("owner", None)
service_specific_id = args.get("service_specific_id", None)
if (provider_service) and (service_specific_id):
- existing_obj = self.get_xos_object(VOLTTenant, kind=VOLT_KIND, provider_service=provider_service, service_specific_id=service_specific_id, throw_exception=False)
+ existing_obj = self.get_xos_object(VOLTTenant, owner=provider_service, service_specific_id=service_specific_id, throw_exception=False)
if existing_obj:
return [ existing_obj ]
return []
def postprocess(self, obj):
- pass
+ subscriber_name = self.get_requirement("tosca.relationships.BelongsToSubscriber")
+ if subscriber_name:
+ subscriber = self.get_xos_object(CordSubscriberRoot, throw_exception=True, name=subscriber_name)
+
+ links = ServiceInstanceLink.objects.filter(provider_service_instance = obj,
+ subscriber_service_instance = subscriber)
+ if not links:
+ link = ServiceInstanceLink(provider_service_instance = obj, subscriber_service_instance = subscriber)
+ link.save()
def can_delete(self, obj):
return super(XOSVOLTTenant, self).can_delete(obj)
diff --git a/xos/volt-onboard.yaml b/xos/volt-onboard.yaml
index 7dd281b..a2a5619 100644
--- a/xos/volt-onboard.yaml
+++ b/xos/volt-onboard.yaml
@@ -18,7 +18,6 @@
admin_template: templates/voltadmin.html
#synchronizer: synchronizer/manifest
tosca_resource: tosca/resources/voltdevice.py, tosca/resources/voltservice.py, tosca/resources/CORDSubscriber.py, tosca/resources/CORDUser.py, tosca/resources/VOLTTenant.py, tosca/resources/accessagent.py, tosca/resources/accessdevice.py
- rest_tenant: subdirectory:cord api/tenant/cord/volt.py, subdirectory:cord api/tenant/cord/subscriber.py
private_key: file:///opt/xos/key_import/volt_rsa
public_key: file:///opt/xos/key_import/volt_rsa.pub
diff --git a/xos/volt.xproto b/xos/volt.xproto
index 3145408..e607a23 100644
--- a/xos/volt.xproto
+++ b/xos/volt.xproto
@@ -5,7 +5,7 @@
option kind = "vOLT";
}
-message VOLTTenant (Tenant){
+message VOLTTenant (ServiceInstance){
option kind = "vOLT";
option verbose_name = "vOLT Tenant";