Merge "Add ML based optimization to PCI opt"
[optf/osdf.git] / apps / slice_selection / optimizers / conductor / response_processor.py
1 # -------------------------------------------------------------------------
2 #   Copyright (C) 2020 Wipro Limited.
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 """
20 Module for processing response from conductor for slice selection
21 """
22
23 from osdf.logging.osdf_logging import debug_log
24
25
26 SLICE_PROFILE_FIELDS = {"latency":"latency", "max_number_of_ues":"maxNumberOfUEs", "coverage_area_ta_list": "coverageAreaTAList",
27                         "ue_mobility_level":"uEMobilityLevel", "resource_sharing_level":"resourceSharingLevel", "exp_data_rate_ul": "expDataRateUL",
28                         "exp_data_rate_dl":"expDataRateDL", "area_traffic_cap_ul":"areaTrafficCapUL", "area_traffic_cap_dl": "areaTrafficCapDL",
29                         "activity_factor":"activityFactor", "e2e_latency":"e2eLatency", "jitter":"jitter", "survival_time": "survivalTime",
30                         "exp_data_rate":"expDataRate", "payload_size":"payloadSize", "traffic_density":"trafficDensity", "conn_density":"connDensity",
31                         "reliability":"reliability", "service_area_dimension":"serviceAreaDimension", "cs_availability": "csAvailability"}
32
33
34 def conductor_response_processor(overall_recommendations, nst_info_map, request_info, service_profile):
35     """Process conductor response to form the response for the API request
36         :param overall_recommendations: recommendations from conductor
37         :param nst_info_map: NST info from the request
38         :param request_info: request info
39         :return: response json as a dictionary
40     """
41     shared_nsi_solutions = list()
42     new_nsi_solutions = list()
43     for nst_name, recommendations in overall_recommendations.items():
44         if  not (recommendations):
45             new_nsi_solution = solution_with_only_slice_profile(service_profile, nst_info_map.get(nst_name))
46             new_nsi_solutions.append(new_nsi_solution)
47             continue
48
49         for recommendation in recommendations:
50             nsi_set = set(values['candidate']['nsi_id'] for key, values in recommendation.items())
51             if len(nsi_set) == 1:
52                 nsi_id = nsi_set.pop()
53                 candidate = list(recommendation.values())[0]['candidate']
54                 debug_log.debug("The NSSIs in the solution belongs to the same NSI {}"
55                                 .format(nsi_id))
56                 shared_nsi_solution = dict()
57                 shared_nsi_solution["NSIId"] = nsi_id
58                 shared_nsi_solution["NSIName"] = candidate.get('nsi_name')
59                 shared_nsi_solution["UUID"] = candidate.get('nsi_model_version_id')
60                 shared_nsi_solution["invariantUUID"] = candidate.get('nsi_model_invariant_id')
61
62                 nssi_info_list = get_nssi_solutions(recommendation)
63                 nssis = list()
64                 for nssi_info in nssi_info_list:
65                     nssi = dict()
66                     nssi["NSSIId"] = nssi_info.get("NSSISolution").get("NSSIId")
67                     nssi["NSSIName"] = nssi_info.get("NSSISolution").get("NSSIName")
68                     nssi["UUID"] = ""
69                     nssi["invariantUUID"] = ""
70                     nssi_info.get("sliceProfile").update({"domainType":"cn"})
71                     nssi["sliceProfile"] = [nssi_info.get("sliceProfile")]
72                     nssis.append(nssi)
73
74                 shared_nsi_solution["NSSIs"] = nssis
75                 shared_nsi_solutions.append(shared_nsi_solution)
76             else:
77                 nssi_solutions = get_nssi_solutions(recommendation)
78                 new_nsi_solution = dict()
79                 new_nsi_solution['matchLevel'] = ""
80                 new_nsi_solution['NSTInfo'] = nst_info_map.get(nst_name)
81                 new_nsi_solution['NSSISolutions'] = nssi_solutions
82                 new_nsi_solutions.append(new_nsi_solution)
83
84     solutions = dict()
85     solutions['sharedNSISolutions'] = shared_nsi_solutions
86     solutions['newNSISolutions'] = new_nsi_solutions
87     return get_nsi_selection_response(request_info, solutions)
88
89
90 def solution_with_only_slice_profile(service_profile, nst_info):
91     nssi_solutions = get_slice_profile_from_service_profile(service_profile)
92     new_nsi_solution = dict()
93     new_nsi_solution['matchLevel'] = ""
94     new_nsi_solution['NSTInfo'] = nst_info
95     new_nsi_solution['NSSISolutions'] = nssi_solutions
96     return new_nsi_solution
97
98 def conductor_error_response_processor(request_info, error_message):
99     """Form response message from the error message
100         :param request_info: request info
101         :param error_message: error message while processing the request
102         :return: response json as dictionary
103     """
104     return {'requestId': request_info['requestId'],
105             'transactionId': request_info['transactionId'],
106             'requestStatus': 'error',
107             'statusMessage': error_message}
108
109
110 def get_slice_profile_from_service_profile(service_profile):
111     nssi_solutions = list()
112     service_profile["domainType"] = "cn"
113     nssi_solution = {"sliceProfile": service_profile}
114     nssi_solutions.append(nssi_solution)
115     return nssi_solutions
116
117
118 def get_nssi_solutions(recommendation):
119     """Get nssi solutions from recommendation
120         :param recommendation: recommendation from conductor
121         :return: new nssi solutions list
122     """
123     nssi_solutions = list()
124
125     for nsst_name, nsst_rec in recommendation.items():
126         candidate = nsst_rec['candidate']
127         nssi_info, slice_profile = get_solution_from_candidate(candidate)
128         nsst_info = {"NSSTName": nsst_name}
129         nssi_solution = {"sliceProfile": slice_profile,
130                          "NSSTInfo": nsst_info,
131                          "NSSISolution": nssi_info}
132         nssi_solutions.append(nssi_solution)
133     return nssi_solutions
134
135
136 def get_solution_from_candidate(candidate):
137     """Get nssi info from candidate
138         :param candidate: Candidate from the recommendation
139         :return: nssi_info and slice profile derived from candidate
140     """
141     slice_profile = dict()
142     nssi_info = {"NSSIName": candidate['instance_name'],
143                  "NSSIId": candidate['candidate_id']}
144
145     for field in SLICE_PROFILE_FIELDS:
146         if candidate[field]:
147             slice_profile[SLICE_PROFILE_FIELDS[field]] = candidate[field]
148
149     return nssi_info, slice_profile
150
151
152 def get_nsi_selection_response(request_info, solutions):
153     """Get NSI selection response from final solution
154         :param request_info: request info
155         :param solutions: final solutions
156         :return: NSI selection response to send back as dictionary
157     """
158     return {'requestId': request_info['requestId'],
159             'transactionId': request_info['transactionId'],
160             'requestStatus': 'completed',
161             'statusMessage': '',
162             'solutions': solutions}
163