blob: f309218d99fb3469f14a6fde81f02d2152731cbb [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
Woojoong Kim8f468142018-01-29 16:31:51 -080081 if blueprint == 'cord_4_1_blueprint':
Woojoong Kim103fba02018-01-18 20:01:06 -080082 return self.get_values_for_CORD_4_1(o)
Woojoong Kim8f468142018-01-29 16:31:51 -080083 elif blueprint == 'cord_5_0_blueprint':
Woojoong Kim103fba02018-01-18 20:01:06 -080084 return self.get_values_for_CORD_5_0(o)
Woojoong Kim8f468142018-01-29 16:31:51 -080085 elif blueprint == 'cord_5_p4_blueprint':
86 return self.get_extra_attributes_for_manual(o) # should be changed to appropriate playbook
Woojoong Kimf000eda2017-10-20 15:00:43 -070087 else:
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -050088 return self.get_extra_attributes_for_manual(o)
Woojoong Kimf000eda2017-10-20 15:00:43 -070089
90 # fields for manual case
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -050091 def get_extra_attributes_for_manual(self, o):
Woojoong Kimf000eda2017-10-20 15:00:43 -070092 fields = {}
Woojoong Kim8f468142018-01-29 16:31:51 -080093 fields['blueprint'] = "manual"
Woojoong Kim103fba02018-01-18 20:01:06 -080094 fields['cord_version'] = "manual"
Woojoong Kimf000eda2017-10-20 15:00:43 -070095 # for interface.cfg file
96 fields['zmq_sub_ip'] = "manual"
97 fields['zmq_pub_ip'] = "manual"
98 fields['dp_comm_ip'] = "manual"
99 fields['cp_comm_ip'] = "manual"
100 fields['fpc_ip'] = "manual"
101 fields['cp_nb_server_ip'] = "manual"
102
103 # for cp_config.cfg file
104 fields['s11_sgw_ip'] = "manual"
105 fields['s11_mme_ip'] = "manual"
106 fields['s1u_sgw_ip'] = "manual"
107
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800108 # for rules setup in ONOS
109 fields['sgi_as_ip'] = "manual"
110 fields['sgi_spgwu_ip'] = "manual"
111
Woojoong Kimf000eda2017-10-20 15:00:43 -0700112 return fields
113
Woojoong Kim103fba02018-01-18 20:01:06 -0800114 def get_values_for_CORD_4_1(self, o):
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700115 fields = {}
Woojoong Kim103fba02018-01-18 20:01:06 -0800116 fields['cord_version'] = "4.1"
Woojoong Kim8f468142018-01-29 16:31:51 -0800117 fields['blueprint'] = "cord_4_1_blueprint"
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700118 # for interface.cfg file
119 fields['zmq_sub_ip'] = "127.0.0.1"
120 fields['zmq_pub_ip'] = "127.0.0.1"
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500121 fields['dp_comm_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500122 'spgw_network', "VSPGWUTenant", o, 'dp_comm_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500123 fields['cp_comm_ip'] = self.get_ip_address_from_peer_service_instance_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500124 'spgw_network', o, o, 'cp_comm_ip')
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700125 fields['fpc_ip'] = "127.0.0.1"
126 fields['cp_nb_server_ip'] = "127.0.0.1"
127
128 # for cp_config.cfg file
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500129 fields['s11_sgw_ip'] = self.get_ip_address_from_peer_service_instance_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500130 's11_network', o, o, 's11_sgw_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500131 fields['s1u_sgw_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500132 's1u_network', "VSPGWUTenant", o, 's1u_sgw_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500133 fields['s11_mme_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500134 's11_network', "VENBServiceInstance", o, 's11_mme_ip')
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700135
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800136 # for rules setup in ONOS
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500137 fields['sgi_as_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500138 'sgi_network', "VENBServiceInstance", o, 'sgi_as_ip')
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500139 fields['sgi_spgwu_ip'] = self.get_ip_address_from_peer_service_instance(
Sapan Bhatia97536292017-11-27 21:35:34 -0500140 'sgi_network', "VSPGWUTenant", o, 'sgi_spgwu_ip')
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800141
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700142 return fields
143
Woojoong Kim103fba02018-01-18 20:01:06 -0800144 def get_values_for_CORD_5_0(self, o):
Woojoong Kim313d35c2017-12-18 17:15:46 -0800145 fields = {}
Woojoong Kim103fba02018-01-18 20:01:06 -0800146 fields['cord_version'] = "5.0"
Woojoong Kim8f468142018-01-29 16:31:51 -0800147 fields['blueprint'] = "cord_5_0_blueprint"
Woojoong Kim313d35c2017-12-18 17:15:46 -0800148
149 # for interface.cfg file
150 fields['zmq_sub_ip'] = "127.0.0.1"
151 fields['zmq_pub_ip'] = "127.0.0.1"
152 fields['dp_comm_ip'] = self.get_ip_address_from_peer_service_instance(
153 'spgw_network', "VSPGWUTenant", o, 'dp_comm_ip')
154 fields['cp_comm_ip'] = self.get_ip_address_from_peer_service_instance_instance(
155 'spgw_network', o, o, 'cp_comm_ip')
156 fields['fpc_ip'] = "127.0.0.1"
157 fields['cp_nb_server_ip'] = "127.0.0.1"
158
159 # for cp_config.cfg file
160 fields['s11_sgw_ip'] = self.get_ip_address_from_peer_service_instance_instance(
161 's11_network', o, o, 's11_sgw_ip')
162 fields['s1u_sgw_ip'] = self.get_ip_address_from_peer_service_instance(
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800163 'flat_network_s1u', "VSPGWUTenant", o, 's1u_sgw_ip')
Woojoong Kim313d35c2017-12-18 17:15:46 -0800164 fields['s11_mme_ip'] = self.get_ip_address_from_peer_service_instance(
165 's11_network', "VMMETenant", o, 's11_mme_ip')
166
167 # for rules setup in ONOS
Woojoong Kim103fba02018-01-18 20:01:06 -0800168 internetemulator_flag = self.has_instance("InternetEmulatorServiceInstance", o)
169 if (internetemulator_flag):
170 fields['sgi_as_ip'] = self.get_ip_address_from_peer_service_instance(
171 'sgi_network', "InternetEmulatorServiceInstance", o, 'sgi_as_ip')
172 else:
173 fields['sgi_as_ip'] = o.appserver_ip_addr
Woojoong Kim313d35c2017-12-18 17:15:46 -0800174 fields['sgi_spgwu_ip'] = self.get_ip_address_from_peer_service_instance(
175 'sgi_network', "VSPGWUTenant", o, 'sgi_spgwu_ip')
176
177 return fields
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500178
179 def find_first_blueprint_subgraph(self, blueprints, adj_set):
180 found_blueprint = None
181 for blueprint in blueprints:
182 found = True
Woojoong Kim313d35c2017-12-18 17:15:46 -0800183
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500184 for node in blueprint['graph']:
185 if node['name'] not in adj_set:
186 found = False
187 break
188 try:
189 links = node['links']
190 except KeyError:
191 links = []
Woojoong Kim313d35c2017-12-18 17:15:46 -0800192
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500193 for link in links:
194 if link['name'] not in adj_set[node['name']]:
195 found = False
196 break
197 if not found:
198 break
Woojoong Kim4f09cbf2017-11-19 21:25:37 -0800199
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500200 if found:
201 found_blueprint = blueprint['name']
202 break
Woojoong Kimf000eda2017-10-20 15:00:43 -0700203
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500204 return found_blueprint
Woojoong Kim313d35c2017-12-18 17:15:46 -0800205
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500206 def check_instance_dependencies(self, blueprints, blueprint_name, o):
207 blueprint = next(
208 b for b in blueprints if b['name'] == blueprint_name)
209 node = next(n for n in blueprint['graph'] if n['name'] == o.leaf_model_name)
Andy Bavier11ff6f52018-01-31 16:01:38 -0700210
211 try:
212 links = node['links']
213 except KeyError:
214 links = []
215
216 for link in links:
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500217 flag = self.has_instance(link['name'], o)
218 if not flag:
219 self.defer_sync('%s does not have an instance. Deferring synchronization.'%link['name'])
Andy Bavier11ff6f52018-01-31 16:01:38 -0700220
Sapan Bhatia0c7f2602018-01-23 23:53:43 -0500221 def get_blueprint_and_check_dependencies(self, o):
222 adj_set = self.adj_set_of_service_graph(o)
223 blueprint_name = self.find_first_blueprint_subgraph(blueprints, adj_set)
224 if blueprint_name:
225 self.check_instance_dependencies(blueprints, blueprint_name, o)
226
227 ret_blueprint = 'manual' if not blueprint_name else blueprint_name
228 return ret_blueprint
Woojoong Kim1a1e3702017-10-27 13:26:34 -0700229
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500230 def get_ip_address_from_peer_service_instance(self, network_name, sitype, o, parameter=None):
231 peer_si = self.get_peer_serviceinstance_of_type(sitype, o)
Sapan Bhatia97536292017-11-27 21:35:34 -0500232 return self.get_ip_address_from_peer_service_instance_instance(network_name, peer_si, o, parameter)
Woojoong Kimf000eda2017-10-20 15:00:43 -0700233
Sapan Bhatia97536292017-11-27 21:35:34 -0500234 def get_ip_address_from_peer_service_instance_instance(self, network_name, peer_si, o, parameter=None):
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500235 try:
236 net_id = self.get_network_id(network_name)
Sapan Bhatia97536292017-11-27 21:35:34 -0500237 ins_id = peer_si.leaf_model.instance_id
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500238 ip_address = Port.objects.get(
239 network_id=net_id, instance_id=ins_id).ip
240 except Exception:
241 self.log.error("Failed to fetch parameter",
242 parameter=parameter,
243 network_name=network_name)
Sapan Bhatia97536292017-11-27 21:35:34 -0500244 self.defer_sync(o, "Waiting for parameters to become available")
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500245
246 return ip_address
247
248 def get_peer_serviceinstance_of_type(self, sitype, o):
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800249
250 global_list = self.get_all_instances_in_graph(o)
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500251
252 try:
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800253 peer_service = next(p for p in global_list if p.leaf_model_name == sitype)
Sapan Bhatia97536292017-11-27 21:35:34 -0500254
Woojoong Kimc96c24f2018-01-22 17:37:05 -0800255 except StopIteration:
256 self.log.error(
257 'Could not find service type in service graph', service_type=sitype, object=o)
258 raise ServiceGraphException(
259 "Synchronization failed due to incomplete service graph")
260
261 return peer_service
262
263 def has_instance_in_list(self, list, o):
264 for instance in list:
265 if instance.leaf_model_name == o.leaf_model_name:
266 return True
267
268 return False
269
270 def get_all_instances_in_graph(self, o):
271
272 to_search_list = self.get_one_hop_instances_in_graph(o)
273 result_list = []
274
275 while len(to_search_list) > 0:
276 tmp_obj = to_search_list[0]
277 to_search_list.remove(tmp_obj)
278 tmp_list = self.get_one_hop_instances_in_graph(tmp_obj)
279
280 for index_obj in tmp_list:
281 if (not self.has_instance_in_list(to_search_list, index_obj)) and (
282 not self.has_instance_in_list(result_list, index_obj)):
283 to_search_list.append(index_obj)
284
285 result_list.append(tmp_obj)
286 return result_list
287
288 def get_one_hop_instances_in_graph(self, o):
289 instance_list = []
290
291 # 1 hop forward and backward
292 prov_links = ServiceInstanceLink.objects.filter(subscriber_service_instance_id=o.id)
293 subs_links = ServiceInstanceLink.objects.filter(provider_service_instance_id=o.id)
294
295 # add instances located in 1 hop into instance_list
296 for tmp_link1 in prov_links:
297 if not self.has_instance_in_list(instance_list, tmp_link1.provider_service_instance):
298 instance_list.append(tmp_link1.provider_service_instance)
299
300 for tmp_link1 in subs_links:
301 if not self.has_instance_in_list(instance_list, tmp_link1.subscriber_service_instance):
302 instance_list.append(tmp_link1.subscriber_service_instance)
303
304 return instance_list
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500305
Woojoong Kimf000eda2017-10-20 15:00:43 -0700306 # To get each network id
307 def get_network_id(self, network_name):
308 return Network.objects.get(name=network_name).id
309
310 # To get service_instance (assumption: there is a single instance for each service)
311 def get_instance_id(self, serviceinstance):
312 instances = serviceinstance.objects.all()
313 instance_id = instances[0].instance_id
314 return instance_id
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500315
316 def has_instance(self, sitype, o):
Sapan Bhatia28b75602017-11-28 14:18:21 -0500317 try:
318 i = self.get_peer_serviceinstance_of_type(sitype, o)
319 except ServiceGraphException:
Sapan Bhatiaa1fbd382017-11-22 13:18:11 -0500320 self.log.info("Missing in ServiceInstance graph",
321 serviceinstance=sitype)
322 return False
323
Woojoong Kim38d84882017-11-28 15:38:39 -0800324 return i.leaf_model.instance_id