CORD-2594: Autodetect blueprints from EPC component services
CORD-2595: Generalize instance dependency checks
Change-Id: I115205f2b74cdf1d28be73455f3f0d983ea55695
diff --git a/xos/synchronizer/steps/sync_vspgwutenant.py b/xos/synchronizer/steps/sync_vspgwutenant.py
index df207af..f56988d 100644
--- a/xos/synchronizer/steps/sync_vspgwutenant.py
+++ b/xos/synchronizer/steps/sync_vspgwutenant.py
@@ -18,29 +18,65 @@
from synchronizers.new_base.modelaccessor import *
from synchronizers.new_base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from collections import defaultdict
+
parentdir = os.path.join(os.path.dirname(__file__), "..")
sys.path.insert(0, parentdir)
-
class ServiceGraphException(Exception):
pass
-
class SyncVSPGWUTenant(SyncInstanceUsingAnsible):
observes = VSPGWUTenant
template_name = "vspgwutenant_playbook.yaml"
service_key_name = "/opt/xos/configurations/mcord/mcord_private_key"
+ """ Convert ServiceInstance graph into an adjacency set"""
+ def adj_set_of_service_graph(self, o, visited = None, adj_set = None):
+ def key(o):
+ return o.leaf_model_name
+
+ if not adj_set:
+ adj_set = defaultdict(set)
+
+ if not o:
+ return adj_set
+ else:
+ if not visited:
+ visited = set()
+
+ ko = key(o)
+ visited.add(ko)
+
+ provider_links = ServiceInstanceLink.objects.filter(subscriber_service_instance_id = o.id)
+ for l in provider_links:
+ n = l.provider_service_instance
+ kn = key(n)
+ adj_set[ko].add(kn)
+ adj_set[kn].update([])
+ if kn not in visited:
+ adj_set = self.adj_set_of_service_graph(n, visited, adj_set)
+
+ subscriber_links = ServiceInstanceLink.objects.filter(provider_service_instance_id = o.id)
+ for l in subscriber_links:
+ n = l.subscriber_service_instance
+ sn = key(n)
+ adj_set[sn].add(ko)
+ adj_set[ko].update([])
+ if sn not in visited:
+ adj_set = self.adj_set_of_service_graph(n, visited, adj_set)
+
+ return adj_set
+
def __init__(self, *args, **kwargs):
super(SyncVSPGWUTenant, self).__init__(*args, **kwargs)
def get_extra_attributes(self, o):
+ blueprint = self.get_blueprint_and_check_dependencies(o)
- scenario = self.get_scenario(o)
-
- if scenario == 'cord_4_1_scenario':
+ if blueprint == 'cord_4_1_blueprint':
return self.get_values_for_CORD_4_1(o)
- elif scenario == 'cord_5_0_scenario':
+ elif blueprint == 'cord_5_0_blueprint':
return self.get_values_for_CORD_5_0(o)
else:
return self.get_extra_attributes_for_manual(o)
@@ -48,7 +84,7 @@
# fields for manual case
def get_extra_attributes_for_manual(self, o):
fields = {}
- fields['scenario'] = "manual"
+ fields['blueprint'] = "manual"
fields['cord_version'] = "manual"
# for interface.cfg file
fields['zmq_sub_ip'] = "manual"
@@ -73,7 +109,7 @@
def get_values_for_CORD_4_1(self, o):
fields = {}
fields['cord_version'] = "4.1"
- fields['scenario'] = "cord_4_1_scenario"
+ fields['blueprint'] = "cord_4_1_blueprint"
# for interface.cfg file
fields['zmq_sub_ip'] = "127.0.0.1"
fields['zmq_pub_ip'] = "127.0.0.1"
@@ -105,7 +141,7 @@
def get_values_for_CORD_5_0(self, o):
fields = {}
fields['cord_version'] = "5.0"
- fields['scenario'] = "cord_5_0_scenario"
+ fields['blueprint'] = "cord_5_0_blueprint"
# for interface.cfg file
fields['zmq_sub_ip'] = "127.0.0.1"
@@ -146,38 +182,52 @@
return i.leaf_model.instance_id
- # Which scenario does it use among Spirent or NG4T?
- def get_scenario(self, o):
- # try get vENB instance: one of both Spirent and NG4T
- venb_flag = self.has_instance("VENBServiceInstance", o)
- vmme_flag = self.has_instance("VMMETenant", o)
- sdncontroller_flag = self.has_instance(
- "SDNControllerServiceInstance", o)
- vspgwc_flag = self.has_instance("VSPGWCTenant", o)
- internetemulator_flag = self.has_instance(
- "InternetEmulatorServiceInstance", o)
- vhss_flag = self.has_instance("VHSSTenant", o)
- hssdb_flag = self.has_instance("HSSDBServiceInstance", o)
+ def find_first_blueprint_subgraph(self, blueprints, adj_set):
+ found_blueprint = None
+ for blueprint in blueprints:
+ found = True
- if (o.blueprint == "build") or (o.blueprint == "MCORD 4.1"):
- if not venb_flag:
- self.defer_sync(o, "Waiting for eNB image to become available")
- if not vspgwc_flag:
- self.defer_sync(o, "Waiting for SPGWC image to become available")
- return 'cord_4_1_scenario'
+ for node in blueprint['graph']:
+ if node['name'] not in adj_set:
+ found = False
+ break
+ try:
+ links = node['links']
+ except KeyError:
+ links = []
- if (o.blueprint == "mcord_5") or (o.blueprint == "MCORD 5"):
- if not hssdb_flag:
- self.defer_sync(o, "Waiting for HSS_DB image to become available")
- if not vhss_flag:
- self.defer_sync(o, "Waiting for vHSS image to become available")
- if not vmme_flag:
- self.defer_sync(o, "Waiting for vMME image to become available")
- if not vspgwc_flag:
- self.defer_sync(o, "Waiting for vSPGWC image to become available")
- return 'cord_5_0_scenario'
+ for link in links:
+ if link['name'] not in adj_set[node['name']]:
+ found = False
+ break
+ if not found:
+ break
- return 'manual'
+ if found:
+ found_blueprint = blueprint['name']
+ break
+
+ return found_blueprint
+
+ def check_instance_dependencies(self, blueprints, blueprint_name, o):
+ blueprint = next(
+ b for b in blueprints if b['name'] == blueprint_name)
+ node = next(n for n in blueprint['graph'] if n['name'] == o.leaf_model_name)
+ for link in node['links']:
+ flag = self.has_instance(link['name'], o)
+ if not flag:
+ self.defer_sync('%s does not have an instance. Deferring synchronization.'%link['name'])
+
+ def get_blueprint_and_check_dependencies(self, o):
+ blueprints = Config().get('blueprints')
+
+ adj_set = self.adj_set_of_service_graph(o)
+ blueprint_name = self.find_first_blueprint_subgraph(blueprints, adj_set)
+ if blueprint_name:
+ self.check_instance_dependencies(blueprints, blueprint_name, o)
+
+ ret_blueprint = 'manual' if not blueprint_name else blueprint_name
+ return ret_blueprint
def get_peer_serviceinstance_of_type(self, sitype, o):
@@ -277,3 +327,4 @@
# To get each network id
def get_network_id(self, network_name):
return Network.objects.get(name=network_name).id
+
diff --git a/xos/synchronizer/vspgwu_config.yaml b/xos/synchronizer/vspgwu_config.yaml
index 5ada1cb..81035b5 100644
--- a/xos/synchronizer/vspgwu_config.yaml
+++ b/xos/synchronizer/vspgwu_config.yaml
@@ -21,3 +21,27 @@
steps_dir: "/opt/xos/synchronizers/vspgwu/steps"
sys_dir: "/opt/xos/synchronizers/vspgwu/sys"
model_policies_dir: "/opt/xos/synchronizers/vspgwu/model_policies"
+blueprints:
+ - name: cord_5_0_blueprint
+ graph:
+ - name: VMMETenant
+ links:
+ - name: VSPGWCTenant
+ links:
+ - name: VMMETenant
+ - name: VSPGWUTenant
+ - name: VSPGWUTenant
+ - name: VHSSTenant
+ links:
+ - name: HSSDBServiceInstance
+ - name: HSSDBServiceInstance
+ - name: cord_4_1_blueprint
+ graph:
+ - name: VSPGWUTenant
+ links:
+ - name: VENBServiceInstance
+ - name: VENBServiceInstance
+ - name: VSPGWCTenant
+ links:
+ - name: VENBServiceInstance
+ - name: VSPGWUTenant
diff --git a/xos/vspgwu.xproto b/xos/vspgwu.xproto
index a914988..23827a9 100644
--- a/xos/vspgwu.xproto
+++ b/xos/vspgwu.xproto
@@ -21,6 +21,5 @@
optional string enodeb_mac_addr = 3 [help_text = "external eNodeB MAC address (for 5.0)", default = "11:11:11:11:11:11", max_length = 32, null = True, db_index = False, blank = True];
optional string appserver_ip_addr = 4 [help_text = "external app server IP address (for 5.0)", default = "127.0.0.1", max_length = 32, null = True, db_index = False, blank = True];
optional string appserver_mac_addr = 5 [help_text = "external app server MAC address (for 5.0)", default = "11:11:11:11:11:11", max_length = 32, null = True, db_index = False, blank = True];
- optional string blueprint = 6 [help_text = "name of blueprint", default = "manual", max_length = 32, null = True, db_index = False, blank = True];
}