changes in OSDF and optimizer for CCVPN get link requirement.
[optf/osdf.git] / apps / route / optimizers / simple_route_opt.py
1 # -------------------------------------------------------------------------
2 #   Copyright (c) 2020 Huawei Intellectual Property
3 #
4 #   Licensed under the Apache License, Version 2.0 (the "License");
5 #   you may not use this file except in compliance with the License.
6 #   You may obtain a copy of the License at
7 #
8 #       http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #   Unless required by applicable law or agreed to in writing, software
11 #   distributed under the License is distributed on an "AS IS" BASIS,
12 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 #   See the License for the specific language governing permissions and
14 #   limitations under the License.
15 #
16 # -------------------------------------------------------------------------
17 #
18
19 import requests
20 from requests.auth import HTTPBasicAuth
21
22 from osdf.utils.mdc_utils import mdc_from_json
23 from osdf.logging.osdf_logging import MH, audit_log, error_log, debug_log
24 import pymzn
25 from sklearn import preprocessing
26
27 import os
28 BASE_DIR = os.path.dirname(__file__)
29
30 class RouteOpt:
31
32     """
33     This values will need to deleted.. 
34     only added for the debug purpose 
35     """
36     # DNS server and standard port of AAI.. 
37     # TODO: read the port from the configuration and add to DNS
38     aai_host = "https://aai.api.simpledemo.onap.org:8443"
39     audit_log.info("base directory")
40     audit_log.info(BASE_DIR)
41     aai_headers = {
42         "X-TransactionId": "9999",
43         "X-FromAppId": "OOF",
44         "Accept": "application/json",
45         "Content-Type": "application/json",
46         "Real-Time": "true"
47     }
48
49     def isCrossONAPLink(self, logical_link):
50         """
51         This method checks if cross link is cross onap
52         :param logical_link:
53         :return:
54         """
55         for relationship in logical_link["relationship-list"]["relationship"]:
56             if relationship["related-to"] == "ext-aai-network":
57                 return True
58         return False
59
60     def getLinksName(self, routes,initial_start_edge,initial_end_edge, mappingTable):
61         routes=list(routes)
62         arr=routes[0]['x']
63         listOfLinks=[]
64         for i in range(0, len(routes[0]['x'])):
65             if arr[i] == 1 :
66                 # listOfLinks.append(self.fetchLogicalLinks(initial_start_edge[i], initial_end_edge[i], mappingTable))
67                 listOfLinks.append(mappingTable[initial_start_edge[i] + ":" + initial_end_edge[i]])
68
69         return listOfLinks
70
71     # def search(self, ip1, ip2, dic):
72     #     if ip1 == "" or ip2 == "":
73     #         return ""
74     #     else:
75     #         string = ip1 + ":" + ip2
76     #         return dic[string]
77     #
78     # def fetchLogicalLinks(self, initial_start_edge, initial_end_edge, mappingTable):
79     #     link_name=self.search(initial_start_edge, initial_end_edge, mappingTable)
80     #     return link_name
81
82
83     # def fetchLogicalLinks(self, initial_start_edge, initial_end_edge, mappingTable):
84     #     return mappingTable[initial_start_edge + ":" + initial_end_edge]
85
86     def solve(self, mzn_model, dzn_data):
87         return pymzn.minizinc(mzn=mzn_model, data=dzn_data)
88
89     def getLinks(self, mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable):
90         routes = self.solve(mzn_model, dzn_data)
91         audit_log.info("mocked minizinc solution====>")
92         audit_log.info(routes)
93
94         converted_links=self.getLinksName(routes, initial_start_edge,initial_end_edge, mappingTable)
95         audit_log.info("converted links===>")
96         audit_log.info(converted_links)
97         return converted_links
98
99     def addition(self, data):
100         relationship = data["relationship-list"]["relationship"]
101         res = ""
102         for index, eachItem in enumerate(relationship):
103             if index == len(relationship) - 1:
104                 res += eachItem["accessNodeId"]
105             else:
106                 res += eachItem["accessNodeId"] + ":"
107
108         return data["link-name"], res
109
110     def createMapTable(self, logical_links):
111         result = map(self.addition, logical_links)
112
113         parseTemplate = {}
114
115         for eachItem in result:
116             parseTemplate[eachItem[1]] = eachItem[0]
117         audit_log.info("mapping table")
118         audit_log.info(parseTemplate)
119         return parseTemplate
120
121     def build_dzn_data(self, src_access_node_id, dst_access_node_id):
122         Edge_Start = []
123         Edge_End = []
124         logical_links = self.get_logical_links()
125         audit_log.info("mocked response of AAI received (logical links) successful===>")
126         audit_log.info(logical_links)
127         # prepare map table
128         mappingTable = self.createMapTable(logical_links)
129         # take the logical link where both the p-interface in same onap
130         if logical_links is not None:
131             for logical_link in logical_links:
132                 if not self.isCrossONAPLink(logical_link):
133                     # link is in local ONAP
134                     relationship = logical_link["relationship-list"]["relationship"]
135
136                     relationshipStartNode = relationship[0]
137                     relationshipStartNodeID = relationshipStartNode["related-link"].split("/")[-1]
138                     start_accessNodeId = relationshipStartNodeID.split("-")[-3]
139                     Edge_Start.append(start_accessNodeId)
140
141                     relationshipEndtNode = relationship[1]
142                     relationshipEndNodeID = relationshipEndtNode["related-link"].split("/")[-1]
143                     end_accessNodeId = relationshipEndNodeID.split("-")[-3]
144                     Edge_End.append(end_accessNodeId)
145
146         audit_log.info("edge start and end array of i/p address are===>")
147         audit_log.info(Edge_Start)
148         audit_log.info(Edge_End)
149         # labeling ip to number for mapping
150         le = preprocessing.LabelEncoder()
151         le.fit(Edge_Start + Edge_End)
152         # print(le.classes_)
153         dzn_start_edge = le.transform(Edge_Start)
154
155         final_dzn_start_arr = []
156         for i in range(0, len(dzn_start_edge)):
157             final_dzn_start_arr.append(dzn_start_edge[i])
158
159         final_dzn_end_arr = []
160         dzn_end_edge = le.transform(Edge_End)
161         for j in range(0, len(dzn_end_edge)):
162             final_dzn_end_arr.append(dzn_end_edge[j])
163
164         audit_log.info("start and end array that passed in dzn_data===>")
165         audit_log.info(final_dzn_start_arr)
166         audit_log.info(final_dzn_end_arr)
167
168         link_cost  = []
169         for k in range(0, len(final_dzn_start_arr)):
170             link_cost.append(1)
171
172         audit_log.info("src_access_node_id")
173         audit_log.info(src_access_node_id)
174         source= le.transform([src_access_node_id])
175         audit_log.info("vallue of source===>")
176         audit_log.info(source)
177         if source in final_dzn_start_arr :
178             start = source[0]
179             audit_log.info("source node")
180             audit_log.info(start)
181
182         audit_log.info("dst_access_node_id")
183         audit_log.info(dst_access_node_id)
184         destination= le.transform([dst_access_node_id])
185         if destination in final_dzn_end_arr :
186             end = destination[0]
187             audit_log.info("destination node")
188             audit_log.info(end)
189         # data to be prepared in the below format:
190         dzn_data = {
191             'N': self.total_node(final_dzn_start_arr + final_dzn_end_arr),
192             'M': len(final_dzn_start_arr),
193             'Edge_Start': final_dzn_start_arr,
194             'Edge_End': final_dzn_end_arr,
195             'L': link_cost,
196             'Start': start,
197             'End': end,
198         }
199         # can not do reverse mapping outside of this scope, so doing here
200         audit_log.info("reverse mapping after prepared dzn_data")
201         initial_start_edge=le.inverse_transform(final_dzn_start_arr)
202         initial_end_edge=le.inverse_transform(final_dzn_end_arr)
203         audit_log.info(initial_start_edge)
204         audit_log.info(initial_end_edge)
205         return dzn_data, initial_start_edge,initial_end_edge, mappingTable
206
207     def total_node(self, node):
208         nodeSet = set()
209         for i in range(0, len(node)):
210             nodeSet.add(node[i])
211         total_node = len(nodeSet)
212         return total_node
213
214     def getRoute(self, request):
215         """
216         This method checks
217         :param logical_link:
218         :return:
219         """
220         routeInfo = request["routeInfo"]["routeRequests"]
221         routeRequest = routeInfo[0]
222         src_access_node_id = routeRequest["srcPort"]["accessNodeId"]
223         dst_access_node_id = routeRequest["dstPort"]["accessNodeId"]
224
225         dzn_data, initial_start_edge, initial_end_edge, mappingTable = self.build_dzn_data(src_access_node_id, dst_access_node_id )
226         #mzn_model = "/home/root1/Videos/projects/osdf/test/functest/simulators/osdf/optimizers/routeopt/route_opt.mzn"
227         mzn_model = os.path.join(BASE_DIR, 'route_opt.mzn')
228
229         routeSolutions = self.getLinks(mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable)
230
231         return {
232             "requestId": request["requestInfo"]["requestId"],
233             "transactionId": request["requestInfo"]["transactionId"],
234             "statusMessage": " ",
235             "requestStatus": "accepted",
236             "solutions": routeSolutions
237         }
238
239     def get_logical_links(self):
240         """
241         This method returns list of all cross ONAP links
242         from /aai/v14/network/logical-links?operation-status="Up"
243         :return: logical-links[]
244         """
245         logical_link_url = "/aai/v13/network/logical-links?operational-status=up"
246         aai_req_url = self.aai_host + logical_link_url
247         response = requests.get(aai_req_url,headers=self.aai_headers,auth=HTTPBasicAuth("AAI", "AAI"),verify=False)
248         if response.status_code == 200:
249             return response.json()