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'),)"];
}