blob: aa1e8b284f7ee433ae1c677a83404010dca95709 [file] [log] [blame]
JianHao4a9550f2017-10-19 11:05:14 +08001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import os
16import sys
Woojoong Kim4f09cbf2017-11-19 21:25:37 -080017import time
JianHao4a9550f2017-10-19 11:05:14 +080018from django.db.models import Q, F
19from synchronizers.new_base.modelaccessor import *
20from synchronizers.new_base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
21
Sapan Bhatia0c7f2602018-01-23 23:53:43 -050022from collections import defaultdict
23
JianHao4a9550f2017-10-19 11:05:14 +080024parentdir = os.path.join(os.path.dirname(__file__), "..")
25sys.path.insert(0, parentdir)
26
Sapan Bhatia0c7f2602018-01-23 23:53:43 -050027blueprints = Config().get('blueprints')
28
Sapan Bhatia28b75602017-11-28 14:18:21 -050029class ServiceGraphException(Exception):
30 pass
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -050031
JianHao4a9550f2017-10-19 11:05:14 +080032class SyncVSPGWCTenant(SyncInstanceUsingAnsible):
JianHao4a9550f2017-10-19 11:05:14 +080033 observes = VSPGWCTenant
JianHao4a9550f2017-10-19 11:05:14 +080034 template_name = "vspgwctenant_playbook.yaml"
JianHao4a9550f2017-10-19 11:05:14 +080035 service_key_name = "/opt/xos/configurations/mcord/mcord_private_key"
36
Sapan Bhatia0c7f2602018-01-23 23:53:43 -050037 """ Convert ServiceInstance graph into an adjacency set"""
38 def adj_set_of_service_graph(self, o, visited = None, adj_set = None):
39 def key(o):
40 return o.leaf_model_name
41
42 if not adj_set:
43 adj_set = defaultdict(set)
44
45 if not o:
46 return adj_set
47 else:
48 if not visited:
49 visited = set()
50
51 ko = key(o)
52 visited.add(ko)
53
54 provider_links = ServiceInstanceLink.objects.filter(subscriber_service_instance_id = o.id)
55 for l in provider_links:
56 n = l.provider_service_instance
57 kn = key(n)
58 adj_set[ko].add(kn)
59 adj_set[kn].update([])
60 if kn not in visited:
61 adj_set = self.adj_set_of_service_graph(n, visited, adj_set)
62
63 subscriber_links = ServiceInstanceLink.objects.filter(provider_service_instance_id = o.id)
64 for l in subscriber_links:
65 n = l.subscriber_service_instance
66 sn = key(n)
67 adj_set[sn].add(ko)
68 adj_set[ko].update([])
69 if sn not in visited:
70 adj_set = self.adj_set_of_service_graph(n, visited, adj_set)
71
72 return adj_set
73
JianHao4a9550f2017-10-19 11:05:14 +080074 def __init__(self, *args, **kwargs):
75 super(SyncVSPGWCTenant, self).__init__(*args, **kwargs)
76
Woojoong Kimf000eda2017-10-20 15:00:43 -070077 def get_extra_attributes(self, o):
JianHao4a9550f2017-10-19 11:05:14 +080078
Sapan Bhatia0c7f2602018-01-23 23:53:43 -050079 blueprint = self.get_blueprint_and_check_dependencies(o)
JianHao4a9550f2017-10-19 11:05:14 +080080
Sapan Bhatia0c7f2602018-01-23 23:53:43 -050081 if blueprint == 'cord_4_1_scenario':
Woojoong Kim103fba02018-01-18 20:01:06 -080082 return self.get_values_for_CORD_4_1(o)
Sapan Bhatia0c7f2602018-01-23 23:53:43 -050083 elif blueprint == 'cord_5_0_scenario':
Woojoong Kim103fba02018-01-18 20:01:06 -080084 return self.get_values_for_CORD_5_0(o)
Woojoong Kimf000eda2017-10-20 15:00:43 -070085 else:
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -050086 return self.get_extra_attributes_for_manual(o)
Woojoong Kimf000eda2017-10-20 15:00:43 -070087
88 # fields for manual case
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -050089 def get_extra_attributes_for_manual(self, o):
Woojoong Kimf000eda2017-10-20 15:00:43 -070090 fields = {}
Woojoong Kim103fba02018-01-18 20:01:06 -080091 fields['scenario'] = "manual"
92 fields['cord_version'] = "manual"
Woojoong Kimf000eda2017-10-20 15:00:43 -070093 # for interface.cfg file
94 fields['zmq_sub_ip'] = "manual"
95 fields['zmq_pub_ip'] = "manual"
96 fields['dp_comm_ip'] = "manual"
97 fields['cp_comm_ip'] = "manual"
98 fields['fpc_ip'] = "manual"
99 fields['cp_nb_server_ip'] = "manual"
100
101 # for cp_config.cfg file
102 fields['s11_sgw_ip'] = "manual"
103 fields['s11_mme_ip'] = "manual"
104 fields['s1u_sgw_ip'] = "manual"
105
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800106 # for rules setup in ONOS
107 fields['sgi_as_ip'] = "manual"
108 fields['sgi_spgwu_ip'] = "manual"
109
Woojoong Kimf000eda2017-10-20 15:00:43 -0700110 return fields
111
Woojoong Kim103fba02018-01-18 20:01:06 -0800112 def get_values_for_CORD_4_1(self, o):
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700113 fields = {}
Woojoong Kim103fba02018-01-18 20:01:06 -0800114 fields['cord_version'] = "4.1"
115 fields['scenario'] = "cord_4_1_scenario"
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700116 # for interface.cfg file
117 fields['zmq_sub_ip'] = "127.0.0.1"
118 fields['zmq_pub_ip'] = "127.0.0.1"
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500119 fields['dp_comm_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500120 'spgw_network', "VSPGWUTenant", o, 'dp_comm_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500121 fields['cp_comm_ip'] = self.get_ip_address_from_peer_service_instance_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500122 'spgw_network', o, o, 'cp_comm_ip')
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700123 fields['fpc_ip'] = "127.0.0.1"
124 fields['cp_nb_server_ip'] = "127.0.0.1"
125
126 # for cp_config.cfg file
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500127 fields['s11_sgw_ip'] = self.get_ip_address_from_peer_service_instance_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500128 's11_network', o, o, 's11_sgw_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500129 fields['s1u_sgw_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500130 's1u_network', "VSPGWUTenant", o, 's1u_sgw_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500131 fields['s11_mme_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500132 's11_network', "VENBServiceInstance", o, 's11_mme_ip')
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700133
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800134 # for rules setup in ONOS
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500135 fields['sgi_as_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500136 'sgi_network', "VENBServiceInstance", o, 'sgi_as_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500137 fields['sgi_spgwu_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500138 'sgi_network', "VSPGWUTenant", o, 'sgi_spgwu_ip')
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800139
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700140 return fields
141
Woojoong Kim103fba02018-01-18 20:01:06 -0800142 def get_values_for_CORD_5_0(self, o):
Woojoong Kim313d35c2017-12-18 17:15:46 -0800143 fields = {}
Woojoong Kim103fba02018-01-18 20:01:06 -0800144 fields['cord_version'] = "5.0"
145 fields['scenario'] = "cord_5_0_scenario"
Woojoong Kim313d35c2017-12-18 17:15:46 -0800146
147 # for interface.cfg file
148 fields['zmq_sub_ip'] = "127.0.0.1"
149 fields['zmq_pub_ip'] = "127.0.0.1"
150 fields['dp_comm_ip'] = self.get_ip_address_from_peer_service_instance(
151 'spgw_network', "VSPGWUTenant", o, 'dp_comm_ip')
152 fields['cp_comm_ip'] = self.get_ip_address_from_peer_service_instance_instance(
153 'spgw_network', o, o, 'cp_comm_ip')
154 fields['fpc_ip'] = "127.0.0.1"
155 fields['cp_nb_server_ip'] = "127.0.0.1"
156
157 # for cp_config.cfg file
158 fields['s11_sgw_ip'] = self.get_ip_address_from_peer_service_instance_instance(
159 's11_network', o, o, 's11_sgw_ip')
160 fields['s1u_sgw_ip'] = self.get_ip_address_from_peer_service_instance(
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800161 'flat_network_s1u', "VSPGWUTenant", o, 's1u_sgw_ip')
Woojoong Kim313d35c2017-12-18 17:15:46 -0800162 fields['s11_mme_ip'] = self.get_ip_address_from_peer_service_instance(
163 's11_network', "VMMETenant", o, 's11_mme_ip')
164
165 # for rules setup in ONOS
Woojoong Kim103fba02018-01-18 20:01:06 -0800166 internetemulator_flag = self.has_instance("InternetEmulatorServiceInstance", o)
167 if (internetemulator_flag):
168 fields['sgi_as_ip'] = self.get_ip_address_from_peer_service_instance(
169 'sgi_network', "InternetEmulatorServiceInstance", o, 'sgi_as_ip')
170 else:
171 fields['sgi_as_ip'] = o.appserver_ip_addr
Woojoong Kim313d35c2017-12-18 17:15:46 -0800172 fields['sgi_spgwu_ip'] = self.get_ip_address_from_peer_service_instance(
173 'sgi_network', "VSPGWUTenant", o, 'sgi_spgwu_ip')
174
175 return fields
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500176
177 def find_first_blueprint_subgraph(self, blueprints, adj_set):
178 found_blueprint = None
179 for blueprint in blueprints:
180 found = True
Woojoong Kim313d35c2017-12-18 17:15:46 -0800181
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500182 for node in blueprint['graph']:
183 if node['name'] not in adj_set:
184 found = False
185 break
186 try:
187 links = node['links']
188 except KeyError:
189 links = []
Woojoong Kim313d35c2017-12-18 17:15:46 -0800190
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500191 for link in links:
192 if link['name'] not in adj_set[node['name']]:
193 found = False
194 break
195 if not found:
196 break
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800197
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500198 if found:
199 found_blueprint = blueprint['name']
200 break
Woojoong Kimf000eda2017-10-20 15:00:43 -0700201
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500202 return found_blueprint
Woojoong Kim313d35c2017-12-18 17:15:46 -0800203
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500204 def check_instance_dependencies(self, blueprints, blueprint_name, o):
205 blueprint = next(
206 b for b in blueprints if b['name'] == blueprint_name)
207 node = next(n for n in blueprint['graph'] if n['name'] == o.leaf_model_name)
208 for link in node['links']:
209 flag = self.has_instance(link['name'], o)
210 if not flag:
211 self.defer_sync('%s does not have an instance. Deferring synchronization.'%link['name'])
212
213 def get_blueprint_and_check_dependencies(self, o):
214 adj_set = self.adj_set_of_service_graph(o)
215 blueprint_name = self.find_first_blueprint_subgraph(blueprints, adj_set)
216 if blueprint_name:
217 self.check_instance_dependencies(blueprints, blueprint_name, o)
218
219 ret_blueprint = 'manual' if not blueprint_name else blueprint_name
220 return ret_blueprint
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700221
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500222 def get_ip_address_from_peer_service_instance(self, network_name, sitype, o, parameter=None):
223 peer_si = self.get_peer_serviceinstance_of_type(sitype, o)
Sapan Bhatia97536292017-11-27 21:35:34 -0500224 return self.get_ip_address_from_peer_service_instance_instance(network_name, peer_si, o, parameter)
Woojoong Kimf000eda2017-10-20 15:00:43 -0700225
Sapan Bhatia97536292017-11-27 21:35:34 -0500226 def get_ip_address_from_peer_service_instance_instance(self, network_name, peer_si, o, parameter=None):
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500227 try:
228 net_id = self.get_network_id(network_name)
Sapan Bhatia97536292017-11-27 21:35:34 -0500229 ins_id = peer_si.leaf_model.instance_id
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500230 ip_address = Port.objects.get(
231 network_id=net_id, instance_id=ins_id).ip
232 except Exception:
233 self.log.error("Failed to fetch parameter",
234 parameter=parameter,
235 network_name=network_name)
Sapan Bhatia97536292017-11-27 21:35:34 -0500236 self.defer_sync(o, "Waiting for parameters to become available")
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500237
238 return ip_address
239
240 def get_peer_serviceinstance_of_type(self, sitype, o):
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800241
242 global_list = self.get_all_instances_in_graph(o)
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500243
244 try:
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800245 peer_service = next(p for p in global_list if p.leaf_model_name == sitype)
Sapan Bhatia97536292017-11-27 21:35:34 -0500246
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800247 except StopIteration:
248 self.log.error(
249 'Could not find service type in service graph', service_type=sitype, object=o)
250 raise ServiceGraphException(
251 "Synchronization failed due to incomplete service graph")
252
253 return peer_service
254
255 def has_instance_in_list(self, list, o):
256 for instance in list:
257 if instance.leaf_model_name == o.leaf_model_name:
258 return True
259
260 return False
261
262 def get_all_instances_in_graph(self, o):
263
264 to_search_list = self.get_one_hop_instances_in_graph(o)
265 result_list = []
266
267 while len(to_search_list) > 0:
268 tmp_obj = to_search_list[0]
269 to_search_list.remove(tmp_obj)
270 tmp_list = self.get_one_hop_instances_in_graph(tmp_obj)
271
272 for index_obj in tmp_list:
273 if (not self.has_instance_in_list(to_search_list, index_obj)) and (
274 not self.has_instance_in_list(result_list, index_obj)):
275 to_search_list.append(index_obj)
276
277 result_list.append(tmp_obj)
278 return result_list
279
280 def get_one_hop_instances_in_graph(self, o):
281 instance_list = []
282
283 # 1 hop forward and backward
284 prov_links = ServiceInstanceLink.objects.filter(subscriber_service_instance_id=o.id)
285 subs_links = ServiceInstanceLink.objects.filter(provider_service_instance_id=o.id)
286
287 # add instances located in 1 hop into instance_list
288 for tmp_link1 in prov_links:
289 if not self.has_instance_in_list(instance_list, tmp_link1.provider_service_instance):
290 instance_list.append(tmp_link1.provider_service_instance)
291
292 for tmp_link1 in subs_links:
293 if not self.has_instance_in_list(instance_list, tmp_link1.subscriber_service_instance):
294 instance_list.append(tmp_link1.subscriber_service_instance)
295
296 return instance_list
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500297
Woojoong Kimf000eda2017-10-20 15:00:43 -0700298 # To get each network id
299 def get_network_id(self, network_name):
300 return Network.objects.get(name=network_name).id
301
302 # To get service_instance (assumption: there is a single instance for each service)
303 def get_instance_id(self, serviceinstance):
304 instances = serviceinstance.objects.all()
305 instance_id = instances[0].instance_id
306 return instance_id
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500307
308 def has_instance(self, sitype, o):
Sapan Bhatia28b75602017-11-28 14:18:21 -0500309 try:
310 i = self.get_peer_serviceinstance_of_type(sitype, o)
311 except ServiceGraphException:
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500312 self.log.info("Missing in ServiceInstance graph",
313 serviceinstance=sitype)
314 return False
315
Woojoong Kim38d84882017-11-28 15:38:39 -0800316 return i.leaf_model.instance_id