Merge "CORD-2281: Configure slices and networks via EPC service"
diff --git a/xos/synchronizer/model_policies/model_policy_vepcserviceinstance.py b/xos/synchronizer/model_policies/model_policy_vepcserviceinstance.py
index 566a4b8..4c81259 100644
--- a/xos/synchronizer/model_policies/model_policy_vepcserviceinstance.py
+++ b/xos/synchronizer/model_policies/model_policy_vepcserviceinstance.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 from synchronizers.new_base.modelaccessor import *
-from synchronizers.new_base.model_policies.model_policy_tenantwithcontainer import TenantWithContainerPolicy, LeastLoadedNodeScheduler
+from synchronizers.new_base.model_policies.model_policy_tenantwithcontainer import Policy
 from synchronizers.new_base.exceptions import *
 
 from xosconfig import Config
@@ -30,9 +30,13 @@
     else:
         raise Exception('Could not translate service instance into service: %s'%si)
 
-class VEPCServiceInstancePolicy(TenantWithContainerPolicy):
+class VEPCServiceInstancePolicy(Policy):
     model_name = "VEPCServiceInstance"
 
+    def __init__(self):
+        self.in_memory_instances = []
+        super(VEPCServiceInstancePolicy, self).__init__()
+
     """TODO: Update the following to not be service-specific
        This code assumes there is only one vendor installed 
     """
@@ -50,6 +54,7 @@
 
     def child_service_instance_from_name(self, name):
         service_instances = self.obj.child_serviceinstances.all() 
+        service_instances.extend(self.in_memory_instances)
 
         try:
             service_instance = next(s for s in service_instances if s.leaf_model_name == name)
@@ -64,17 +69,19 @@
         service_obj = service_class.objects.first() # There's only one service object
         return service_obj
 
-    def create_service_instance(si):
+    def create_service_instance(self, si):
         service = self.get_service_for_service_instance(si)
 	if not service:
 	    raise Exception('No service object for %s'%service)
 
 	si_class = getattr(Slice().stub, si)
-	s = si_class(owner = service, name = 'epc-' + si.lower())
+	s = si_class(owner = service, name = 'epc-%s-%d'%(si.lower(), self.obj.id))
 	s.master_serviceinstance = self.obj
 
 	self.configure_service_instance(s)
 	s.save()
+
+        self.in_memory_instances.append(s)
         return s
 
     def create_link(self, src, dst):
@@ -100,14 +107,14 @@
             service_instance_link.save()
 
     def recursive_create_links(self, blueprint, src):
-        for k, v in blueprint.iteritems():
-            if src:
-                self.create_link(src, k)
+	for k, v in blueprint.iteritems():
+	    if src:
+		self.create_link(src, k)
 
-            if isinstance(v, dict):
-                self.recursive_create_links(v, k)
-            else:
-                self.create_link(src, k)
+	    if isinstance(v, dict):
+		self.recursive_create_links(v, k)
+	    else:
+		self.create_link(k, v)
 
     def create_child_services(self, service_instance):
         self.obj = service_instance
@@ -120,152 +127,11 @@
 
         self.recursive_create_links(blueprint['graph'], None)
 
+    def handle_create(self, service_instance):
+        self.handle_update(service_instance)
+
     def handle_update(self, service_instance):
         self.create_child_services(service_instance)
 
-        if (service_instance.link_deleted_count > 0) and (not service_instance.provided_links.exists()):
-            self.logger.info(
-                "The last provided link has been deleted -- self-destructing.")
-            self.handle_delete(service_instance)
-            if VEPCServiceInstance.objects.filter(id=service_instance.id).exists():
-                service_instance.delete()
-            else:
-                self.logger.info("Tenant %s is already deleted" %
-                                 service_instance)
-            return
-
-        self.manage_container(service_instance)
-
     def handle_delete(self, service_instance):
-        if service_instance.instance and (not service_instance.instance.deleted):
-            all_service_instances_this_instance = VEPCServiceInstance.objects.filter(
-                instance_id=service_instance.instance.id)
-            other_service_instances_this_instance = [
-                x for x in all_service_instances_this_instance if x.id != service_instance.id]
-            if (not other_service_instances_this_instance):
-                self.logger.info(
-                    "VEPCServiceInstance Instance %s is now unused -- deleting" % service_instance.instance)
-                self.delete_instance(
-                    service_instance, service_instance.instance)
-            else:
-                self.logger.info("VEPCServiceInstance Instance %s has %d other service instances attached" % (
-                    service_instance.instance, len(other_service_instances_this_instance)))
-
-    def get_service(self, service_instance):
-        service_name = service_instance.owner.leaf_model_name
-        service_class = globals()[service_name]
-        return service_class.objects.get(id=service_instance.owner.id)
-
-    def find_instance_for_instance_tag(self, instance_tag):
-        tags = Tag.objects.filter(name="instance_tag", value=instance_tag)
-        if tags:
-            return tags[0].content_object
-        return None
-
-    def find_or_make_instance_for_instance_tag(self, service_instance):
-        instance_tag = self.get_instance_tag(service_instance)
-        instance = self.find_instance_for_instance_tag(instance_tag)
-        if instance:
-            if instance.no_sync:
-                # if no_sync is still set, then perhaps we failed while saving it and need to retry.
-                self.save_instance(service_instance, instance)
-            return instance
-
-        desired_image = self.get_image(service_instance)
-        desired_flavor = self.get_flavor(service_instance)
-
-        slice = service_instance.owner.slices.first()
-
-        (node, parent) = LeastLoadedNodeScheduler(slice, label=None).pick()
-
-        assert (slice is not None)
-        assert (node is not None)
-        assert (desired_image is not None)
-        assert (service_instance.creator is not None)
-        assert (node.site_deployment.deployment is not None)
-        assert (desired_image is not None)
-
-        instance = Instance(slice=slice,
-                            node=node,
-                            image=desired_image,
-                            creator=service_instance.creator,
-                            deployment=node.site_deployment.deployment,
-                            flavor=flavors[0],
-                            isolation=slice.default_isolation,
-                            parent=parent)
-
-        self.save_instance(service_instance, instance)
-
-        return instance
-
-    def manage_container(self, service_instance):
-        if service_instance.deleted:
-            return
-
-        if service_instance.instance:
-            # We're good.
-            return
-
-        instance = self.find_or_make_instance_for_instance_tag(
-            service_instance)
-        service_instance.instance = instance
-        # TODO: possible for partial failure here?
-        service_instance.save()
-
-    def delete_instance(self, service_instance, instance):
-        # delete the `instance_tag` tags
-        tags = Tag.objects.filter(service_id=service_instance.owner.id, content_type=instance.self_content_type_id,
-                                  object_id=instance.id, name="instance_tag")
-        for tag in tags:
-            tag.delete()
-
-        tags = Tag.objects.filter(content_type=instance.self_content_type_id, object_id=instance.id,
-                                  name="vm_vrouter_tenant")
-        for tag in tags:
-            address_manager_instances = list(
-                ServiceInstance.objects.filter(id=tag.value))
-            tag.delete()
-
-            # TODO: Potential partial failure
-
-            for address_manager_instance in address_manager_instances:
-                self.logger.info(
-                    "Deleting address_manager_instance %s" % address_manager_instance)
-                address_manager_instance.delete()
-
-        instance.delete()
-
-    def save_instance(self, service_instance, instance):
-        instance.volumes = "/etc/dnsmasq.d,/etc/ufw"
-        instance.no_sync = True   # prevent instance from being synced until we're done with it
-        super(VEPCServiceInstancePolicy, self).save_instance(instance)
-
-        try:
-            if instance.isolation in ["container", "container_vm"]:
-                raise Exception("Not supported")
-
-            instance_tag = self.get_instance_tag(service_instance)
-
-            if instance_tag:
-                tags = Tag.objects.filter(
-                    name="instance_tag", value=instance_tag)
-                if not tags:
-                    tag = Tag(service=service_instance.owner, content_type=instance.self_content_type_id,
-                              object_id=instance.id, name="instance_tag", value=str(instance_tag))
-                    tag.save()
-
-            instance.no_sync = False   # allow the synchronizer to run now
-            super(VEPCServiceInstancePolicy, self).save_instance(instance)
-        except:
-            # need to clean up any failures here
-            raise
-
-    def get_instance_tag(self, service_instance):
-        return '%d'%service_instance.id
-
-    def get_image(self, service_instance):
-        return None
-
-    def get_flavor(self, service_instance):
-        raise None
-
+	raise Exception("Not implemented")
diff --git a/xos/vepc.xproto b/xos/vepc.xproto
index 3a23d6b..c67e991 100644
--- a/xos/vepc.xproto
+++ b/xos/vepc.xproto
@@ -1,15 +1,13 @@
-option name = "vEPC";
-option verbose_name = "Virtual Evolved Packet Core";
+option name = "vepc";
 option app_label = "vepc";
 
 message VEPCService (Service){
-    option name = "VEPCService";
     option verbose_name = "Virtual Evolved Packet Core Service";
 }
 
 message VEPCServiceInstance (TenantWithContainer){
-    option name = "VEPCServiceInstance";
     option verbose_name = "Virtual Evolved Packet Core ServiceInstance";
     optional string description = 1 [help_text = "service chain details", max_length = 128, null = True, db_index = False, blank = True];
-    required string blueprint = 3 [help_text = "Select the service graph blueprint", db_index = False, default = 1, choices = "(('build', 'CORD Build'),)"];
+    required manytoone site->Site:+ = 2 [help_text = "Site of the EPC Service", null = False, db_index = True, blank = False];
+    required string blueprint = 3 [help_text = "Select the service graph blueprint", db_index = False, default = 1, choices = "(('build', 'MCORD 4.1'),)"];
 }