[CORD-1725] Implement Service Chaining (EPC-as-a-Service)

Change-Id: Ic5f3f312d7734f527d6937406cb59efbdbb8b443
diff --git a/xos/models.py b/xos/models.py
index 3c8cf20..8bd0c46 100644
--- a/xos/models.py
+++ b/xos/models.py
@@ -12,6 +12,9 @@
 from operator import itemgetter, attrgetter, methodcaller
 from core.models import Tag
 from core.models.service import LeastLoadedNodeScheduler
+from services.vsgw.models import VSGWService, VSGWTenant
+from services.vpgwc.models import VPGWCService, VPGWCTenant
+from services.vhss.models import VHSSService, VHSSTenant
 import traceback
 from xos.exceptions import *
 from xos.config import Config
@@ -27,11 +30,142 @@
         proxy = True 
 
    def __init__(self, *args, **kwargs):
-       vmmeservice = VMMEService.get_service_objects().all()
-       if vmmeservice:
-           self._meta.get_field(
-                   "provider_service").default = vmmeservice[0].id
+       vmmeservices = VMMEService.get_service_objects().all()
+       if vmmeservices:
+           self._meta.get_field("provider_service").default = vmmeservices[0].id
        super(VMMETenant, self).__init__(*args, **kwargs)
+       self.cached_vsgw = None
+       self.cached_vpgwc = None
+       self.cached_vhss = None
+
+   @property
+   def vsgw(self):
+       vsgw = self.get_newest_subscribed_tenant(VSGWTenant)
+       if not vsgw:
+           return None
+
+       if (self.cached_vsgw) and (self.cached_vsgw.id == vsgw.id):
+            return self.cached_vsgw
+
+       vsgw.caller = self.creator
+       self.cached_vsgw = vsgw
+       return vsgw      
+
+   @vsgw.setter
+   def vsgw(self, value):
+       raise XOSConfigurationError("VMMETenant.vsgw setter is not implemeneted")
+
+   @property
+   def vpgwc(self):
+       vpgwc = self.get_newest_subscribed_tenant(VPGWCTenant)
+       if not vpgwc:
+           return None
+
+       if (self.cached_vpgwc) and (self.cached_vpgwc.id == vpgwc.id):
+            return self.cached_vpgwc
+
+       vpgwc.caller = self.creator
+       self.cached_vpgwc = vpgwc
+       return vpgwc      
+
+   @vpgwc.setter
+   def vpgwc(self, value):
+       raise XOSConfigurationError("VMMETenant.vpgwc setter is not implemeneted")
+
+   @property
+   def vhss(self):
+       vhss = self.get_newest_subscribed_tenant(VHSSTenant)
+       if not vhss:
+           return None
+
+       if (self.cached_vhss) and (self.cached_vhss.id == vhss.id):
+            return self.cached_vhss
+
+       vhss.caller = self.creator
+       self.cached_vhss = vhss
+       return vhss      
+
+   @vhss.setter
+   def vhss(self, value):
+       raise XOSConfigurationError("VMMETenant.vhss setter is not implemeneted")
+
+   # This model breaks down if there are multiple service objects
+   def get_vsgw_service(self):
+       vsgwservices = VSGWService.get_service_objects().all()
+       if not vsgwservices:
+           raise XOSConfigurationError("No VSGW Services available")
+       return vsgwservices[0]
+
+   def get_vpgwc_service(self):
+       vpgwcservices = VPGWCService.get_service_objects().all()
+       if not vpgwcservices:
+           raise XOSConfigurationError("No VPGWC Services available")
+       return vpgwcservices[0]
+
+   def get_vhss_service(self):
+       vhssservices = VHSSService.get_service_objects().all()
+       if not vhssservices:
+           raise XOSConfigurationError("No VHSS Services available")
+       return vhssservices[0]
+
+   def manage_vsgw(self):
+       # Each vMME object owns exactly one VSGWTenant object
+       if self.deleted:
+           return
+
+       if self.vsgw is None:
+           vsgw = self.get_vsgw_service().create_tenant(subscriber_tenant=self, creator=self.creator)
+
+   def manage_vpgwc(self):
+       # Each vMME object owns exactly one VPGWCTenant object
+       if self.deleted:
+           return
+
+       if self.vpgwc is None:
+           vpgwc = self.get_vpgwc_service().create_tenant(subscriber_tenant=self, creator=self.creator)
+
+   def manage_vhss(self):
+       # Each vMME object owns exactly one VHSSTenant object
+       if self.deleted:
+           return
+
+       if self.vhss is None:
+           vhss = self.get_vhss_service().create_tenant(subscriber_tenant=self, creator=self.creator)
+
+   def cleanup_vsgw(self):
+       if self.vsgw:
+           self.vsgw.delete()
+
+   def cleanup_vpgwc(self):
+       if self.vpgwc:
+           self.vpgwc.delete()
+
+   def cleanup_vhss(self):
+       if self.vhss:
+           self.vhss.delete()
+  
+   def cleanup_orphans(self):
+       # ensure vMME only has one vSGW, vPGWC, and vHSS
+       cur_vsgw = self.vsgw
+       cur_vpgwc = self.vpgwc
+       cur_vhss = self.vhss
+
+       for vsgw in list(self.get_subscribed_tenants(VSGWTenant)):
+           if (not cur_vsgw) or (vsgw.id != cur_vsgw.id):
+              vsgw.delete()
+
+       for vpgwc in list(self.get_subscribed_tenants(VPGWCTenant)):
+           if (not cur_vpgwc) or (vpgwc.id != cur_vpgwc.id):
+              vpgwc.delete()
+
+       for vhss in list(self.get_subscribed_tenants(VHSSTenant)):
+           if (not cur_vhss) or (vhss.id != cur_vhss.id):
+              vhss.delete()
+
+       if self.orig_instance_id and (self.orig_instance_id != self.get_attribute("instance_id")):
+           instances = Instance.objects.filter(id=self.orig_instance.id)
+           if instances:
+               instances[0].delete()
 
    def save(self, *args, **kwargs):
        super(VMMETenant, self).save(*args, **kwargs)
@@ -41,6 +175,9 @@
 
    def delete(self, *args, **kwargs):
        # Delete the instance that was created for this tenant
+       self.cleanup_vsgw()
+       self.cleanup_vpgwc()
+       self.cleanup_vhss()
        self.cleanup_container()
        super(VMMETenant, self).delete(*args, **kwargs)
 
@@ -54,3 +191,7 @@
         # Since this code is atomic it is safe to always use the first tenant
         tenant = tenant[0]
         tenant.manage_container()
+        tenant.manage_vsgw()
+        tenant.manage_vpgwc()
+        tenant.manage_vhss()
+        tenant.cleanup_orphans()