aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSithara Nambiar <sitharav.aredath@huawei.com>2020-04-20 21:39:33 +0530
committerSithara Nambiar <sitharav.aredath@huawei.com>2020-04-21 13:53:52 +0530
commit2ac2b0c1c177dfec588b9c3439a41340d555897b (patch)
tree43be48a427e21af985979d5f4f04a0f4c99cb0cf
parenta5d124e5fa47a7ff5a0717a1b2e160bb766169b7 (diff)
Route optimization -take 2
Issue-ID: OPTFRA-420 Signed-off-by: Sithara Nambiar <sitharav.aredath@huawei.com> Change-Id: I06624f5adee060ce220a82f2a05a17c0986ca904
-rw-r--r--apps/route/optimizers/simple_route_opt.py149
-rwxr-xr-xconfig/osdf_config.yaml4
-rwxr-xr-xosdfapp.py2
-rwxr-xr-xtest/functest/simulators/simulated-config/osdf_config.yaml3
-rw-r--r--test/simple_route_opt/AAI.json164
-rw-r--r--test/simple_route_opt/routeOpt.json34
-rw-r--r--test/test_simple_route_opt.py57
7 files changed, 346 insertions, 67 deletions
diff --git a/apps/route/optimizers/simple_route_opt.py b/apps/route/optimizers/simple_route_opt.py
index 27c1141..9113516 100644
--- a/apps/route/optimizers/simple_route_opt.py
+++ b/apps/route/optimizers/simple_route_opt.py
@@ -17,6 +17,7 @@
#
import requests
+import json
from requests.auth import HTTPBasicAuth
from osdf.utils.mdc_utils import mdc_from_json
@@ -35,18 +36,14 @@ class RouteOpt:
"""
# DNS server and standard port of AAI..
# TODO: read the port from the configuration and add to DNS
- aai_host = "https://aai.api.simpledemo.onap.org:8443"
- audit_log.info("base directory")
- audit_log.info(BASE_DIR)
aai_headers = {
"X-TransactionId": "9999",
"X-FromAppId": "OOF",
"Accept": "application/json",
"Content-Type": "application/json",
- "Real-Time": "true"
}
- def isCrossONAPLink(self, logical_link):
+ def is_cross_onap_link(self, logical_link):
"""
This method checks if cross link is cross onap
:param logical_link:
@@ -57,57 +54,54 @@ class RouteOpt:
return True
return False
- def getLinksName(self, routes,initial_start_edge,initial_end_edge, mappingTable):
+ def get_links_name(self, routes,initial_start_edge,initial_end_edge, mappingTable):
routes=list(routes)
- arr=routes[0]['x']
+ try:
+ arr=routes[0]['x']
+ except Exception as err:
+ audit_log.info("No satisfiable solutions found")
+ raise err
listOfLinks=[]
for i in range(0, len(routes[0]['x'])):
+ individual_link = {}
if arr[i] == 1 :
# listOfLinks.append(self.fetchLogicalLinks(initial_start_edge[i], initial_end_edge[i], mappingTable))
- listOfLinks.append(mappingTable[initial_start_edge[i] + ":" + initial_end_edge[i]])
+ individual_link["link"] = mappingTable[initial_start_edge[i] + ":" + initial_end_edge[i]]
+ individual_link["start_node"] = initial_start_edge[i]
+ individual_link["end_node"] = initial_end_edge[i]
+ listOfLinks.append(individual_link)
return listOfLinks
- # def search(self, ip1, ip2, dic):
- # if ip1 == "" or ip2 == "":
- # return ""
- # else:
- # string = ip1 + ":" + ip2
- # return dic[string]
- #
- # def fetchLogicalLinks(self, initial_start_edge, initial_end_edge, mappingTable):
- # link_name=self.search(initial_start_edge, initial_end_edge, mappingTable)
- # return link_name
-
-
- # def fetchLogicalLinks(self, initial_start_edge, initial_end_edge, mappingTable):
- # return mappingTable[initial_start_edge + ":" + initial_end_edge]
-
def solve(self, mzn_model, dzn_data):
return pymzn.minizinc(mzn=mzn_model, data=dzn_data)
- def getLinks(self, mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable):
+ def get_links(self, mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable):
routes = self.solve(mzn_model, dzn_data)
audit_log.info("mocked minizinc solution====>")
audit_log.info(routes)
- converted_links=self.getLinksName(routes, initial_start_edge,initial_end_edge, mappingTable)
+ converted_links=self.get_links_name(routes, initial_start_edge,initial_end_edge, mappingTable)
audit_log.info("converted links===>")
audit_log.info(converted_links)
return converted_links
def addition(self, data):
- relationship = data["relationship-list"]["relationship"]
res = ""
- for index, eachItem in enumerate(relationship):
- if index == len(relationship) - 1:
- res += eachItem["accessNodeId"]
- else:
- res += eachItem["accessNodeId"] + ":"
-
- return data["link-name"], res
-
- def createMapTable(self, logical_links):
+ if 'relationship-list' in data.keys():
+ relationship = data["relationship-list"]["relationship"]
+ for index, eachItem in enumerate(relationship):
+ temp = eachItem["relationship-data"][0]
+ if index == len(relationship) - 1:
+ res += temp['relationship-value']
+ else:
+ res += temp['relationship-value'] + ":"
+
+ return data["link-name"], res
+ else:
+ return data["link-name"], res
+
+ def create_map_table(self, logical_links):
result = map(self.addition, logical_links)
parseTemplate = {}
@@ -118,30 +112,47 @@ class RouteOpt:
audit_log.info(parseTemplate)
return parseTemplate
- def build_dzn_data(self, src_access_node_id, dst_access_node_id):
+ def build_dzn_data(self, src_access_node_id, dst_access_node_id, osdf_config):
Edge_Start = []
Edge_End = []
- logical_links = self.get_logical_links()
+ logical_links = self.get_logical_links(osdf_config)
+
+
+ logical_links = logical_links['logical-link']
audit_log.info("mocked response of AAI received (logical links) successful===>")
audit_log.info(logical_links)
# prepare map table
- mappingTable = self.createMapTable(logical_links)
+ mappingTable = self.create_map_table(logical_links)
+ audit_log.info("mapping table created successfully====>")
+ audit_log.info(mappingTable)
# take the logical link where both the p-interface in same onap
if logical_links is not None:
+ audit_log.info('logical links not empty=====>')
for logical_link in logical_links:
- if not self.isCrossONAPLink(logical_link):
- # link is in local ONAP
- relationship = logical_link["relationship-list"]["relationship"]
-
- relationshipStartNode = relationship[0]
- relationshipStartNodeID = relationshipStartNode["related-link"].split("/")[-1]
- start_accessNodeId = relationshipStartNodeID.split("-")[-3]
- Edge_Start.append(start_accessNodeId)
-
- relationshipEndtNode = relationship[1]
- relationshipEndNodeID = relationshipEndtNode["related-link"].split("/")[-1]
- end_accessNodeId = relationshipEndNodeID.split("-")[-3]
- Edge_End.append(end_accessNodeId)
+ audit_log.info('logical_link')
+ audit_log.info(logical_link)
+
+ if 'relationship-list' in logical_link.keys():
+ if not self.is_cross_onap_link(logical_link):
+ # link is in local ONAP
+ audit_log.info('link is inside onap===>')
+ relationship = logical_link["relationship-list"]["relationship"]
+
+ relationshipStartNode = relationship[0]
+ audit_log.info('relationshipStartNode')
+ audit_log.info(relationshipStartNode)
+ relationshipStartNodeID = relationshipStartNode["related-link"].split("/")[-4]
+ audit_log.info('relationshipStartNodeID')
+ audit_log.info(relationshipStartNodeID)
+ Edge_Start.append(relationshipStartNodeID)
+
+ relationshipEndtNode = relationship[1]
+ relationshipEndNodeID = relationshipEndtNode["related-link"].split("/")[-4]
+ audit_log.info('relationshipEndNodeID')
+ audit_log.info(relationshipEndNodeID)
+ Edge_End.append(relationshipEndNodeID)
+ else:
+ continue
audit_log.info("edge start and end array of i/p address are===>")
audit_log.info(Edge_Start)
@@ -149,7 +160,6 @@ class RouteOpt:
# labeling ip to number for mapping
le = preprocessing.LabelEncoder()
le.fit(Edge_Start + Edge_End)
- # print(le.classes_)
dzn_start_edge = le.transform(Edge_Start)
final_dzn_start_arr = []
@@ -211,39 +221,46 @@ class RouteOpt:
total_node = len(nodeSet)
return total_node
- def getRoute(self, request):
+ def get_route(self, request, osdf_config):
"""
This method checks
:param logical_link:
:return:
"""
- routeInfo = request["routeInfo"]["routeRequests"]
- routeRequest = routeInfo[0]
- src_access_node_id = routeRequest["srcPort"]["accessNodeId"]
- dst_access_node_id = routeRequest["dstPort"]["accessNodeId"]
+ try:
+ routeInfo = request["routeInfo"]["routeRequests"]
+ routeRequest = routeInfo[0]
+ src_access_node_id = routeRequest["srcPort"]["accessNodeId"]
+ dst_access_node_id = routeRequest["dstPort"]["accessNodeId"]
- dzn_data, initial_start_edge, initial_end_edge, mappingTable = self.build_dzn_data(src_access_node_id, dst_access_node_id )
- #mzn_model = "/home/root1/Videos/projects/osdf/test/functest/simulators/osdf/optimizers/routeopt/route_opt.mzn"
- mzn_model = os.path.join(BASE_DIR, 'route_opt.mzn')
+ dzn_data, initial_start_edge, initial_end_edge, mappingTable = self.build_dzn_data(src_access_node_id, dst_access_node_id, osdf_config)
+ #mzn_model = "/home/root1/Videos/projects/osdf/test/functest/simulators/osdf/optimizers/routeopt/route_opt.mzn"
+ mzn_model = os.path.join(BASE_DIR, 'route_opt.mzn')
- routeSolutions = self.getLinks(mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable)
+ routeSolutions = self.get_links(mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable)
- return {
+ return {
"requestId": request["requestInfo"]["requestId"],
"transactionId": request["requestInfo"]["transactionId"],
"statusMessage": " ",
"requestStatus": "accepted",
"solutions": routeSolutions
- }
+ }
+ except Exception as err:
+ audit_log.info(err)
+ raise err
- def get_logical_links(self):
+ def get_logical_links(self, osdf_config):
"""
This method returns list of all cross ONAP links
from /aai/v14/network/logical-links?operation-status="Up"
:return: logical-links[]
"""
- logical_link_url = "/aai/v13/network/logical-links?operational-status=up"
- aai_req_url = self.aai_host + logical_link_url
+
+ config = osdf_config.deployment
+ aai_url = config["aaiUrl"]
+ aai_req_url = aai_url + config["aaiGetLinksUrl"]
+
response = requests.get(aai_req_url,headers=self.aai_headers,auth=HTTPBasicAuth("AAI", "AAI"),verify=False)
if response.status_code == 200:
return response.json() \ No newline at end of file
diff --git a/config/osdf_config.yaml b/config/osdf_config.yaml
index c7c5898..4802a67 100755
--- a/config/osdf_config.yaml
+++ b/config/osdf_config.yaml
@@ -50,6 +50,10 @@ configDbUrl: http://config.db.url:8080
configDbGetCellListUrl: 'SDNCConfigDBAPI/getCellList'
configDbGetNbrListUrl: 'SDNCConfigDBAPI/getNbrList'
+#aai api
+aaiUrl: "https://aai.url:30233"
+aaiGetLinksUrl: "/aai/v16/network/logical-links"
+
pciHMSUsername: test
pciHMSPassword: passwd
diff --git a/osdfapp.py b/osdfapp.py
index fdc2c1d..1099e55 100755
--- a/osdfapp.py
+++ b/osdfapp.py
@@ -101,7 +101,7 @@ def do_route_calc():
"""
request_json = request.get_json()
audit_log.info("Calculate Route request received!")
- response = RouteOpt().getRoute(request_json)
+ response = RouteOpt().get_route(request_json, osdf_config)
return response
@app.route("/api/oof/v1/selection/nst", methods=["POST"])
diff --git a/test/functest/simulators/simulated-config/osdf_config.yaml b/test/functest/simulators/simulated-config/osdf_config.yaml
index eccad14..414d7c7 100755
--- a/test/functest/simulators/simulated-config/osdf_config.yaml
+++ b/test/functest/simulators/simulated-config/osdf_config.yaml
@@ -71,3 +71,6 @@ configDbGetNbrListUrl: 'getNbrList'
pciHMSUsername: "" # pcihandler username for call back.
pciHMSPassword: "" # pcihandler password for call back.
+aaiUrl: "https://api.url:30233"
+aaiGetLinksUrl: "/aai/v16/network/logical-links"
+
diff --git a/test/simple_route_opt/AAI.json b/test/simple_route_opt/AAI.json
new file mode 100644
index 0000000..6ef264b
--- /dev/null
+++ b/test/simple_route_opt/AAI.json
@@ -0,0 +1,164 @@
+{
+ "logical-link": [
+ {
+ "link-name": "link-id-1",
+ "in-maint": true,
+ "link-type": "example-link-type-val-16287",
+ "resource-version": "1585009311719",
+ "operational-status": "UP",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/20.20.20.20/p-interfaces/p-interface/p-interface-3",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "20.20.20.20"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-3"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/10.10.10.10/p-interfaces/p-interface/p-interface-2",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "10.10.10.10"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-2"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name": "link-id-2",
+ "in-maint": true,
+ "link-type": "example-link-type-val-16287",
+ "resource-version": "1584943281792",
+ "operational-status": "UP",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/22.22.22.22/p-interfaces/p-interface/p-interface-7",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "22.22.22.22"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-7"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/11.11.11.11/p-interfaces/p-interface/p-interface-6",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "11.11.11.11"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-6"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name": "link-id-3",
+ "in-maint": true,
+ "link-type": "example-link-type-val-16287",
+ "resource-version": "1584943345290",
+ "operational-status": "UP",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/11.11.11.11/p-interfaces/p-interface/p-interface-5",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "11.11.11.11"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-5"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/20.20.20.20/p-interfaces/p-interface/p-interface-4",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "20.20.20.20"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-4"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name": "rahul",
+ "in-maint": true,
+ "link-type": "example-link-type-val-rahul",
+ "resource-version": "1585023629505",
+ "operational-status": "UP"
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/simple_route_opt/routeOpt.json b/test/simple_route_opt/routeOpt.json
new file mode 100644
index 0000000..887b85b
--- /dev/null
+++ b/test/simple_route_opt/routeOpt.json
@@ -0,0 +1,34 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestId": "yyy-yyy-yyyy",
+ "callbackUrl": "https://wiki.onap.org:5000/callbackUrl",
+ "sourceId": "",
+ "requestType": "create",
+ "numSolutions": 1,
+ "optimizers": [
+ "route"
+ ],
+ "timeout": 600
+ },
+ "routeInfo": {
+ "routeRequests": [
+ {
+ "srcPort": {
+ "accessTopologyId": "Topo113",
+ "accessClientId": "clientU12",
+ "accessProviderId": "VDF1234",
+ "accessNodeId": "22.22.22.22",
+ "accessLtpId": "1345"
+ },
+ "dstPort": {
+ "accessTopologyId": "Topo3421",
+ "accessClientId": "clientD123",
+ "accessProviderId": "VDF3214",
+ "accessNodeId": "10.10.10.10",
+ "accessLtpId": "3452"
+ }
+ }
+ ]
+ }
+}
diff --git a/test/test_simple_route_opt.py b/test/test_simple_route_opt.py
new file mode 100644
index 0000000..3b4facc
--- /dev/null
+++ b/test/test_simple_route_opt.py
@@ -0,0 +1,57 @@
+from apps.route.optimizers.simple_route_opt import RouteOpt
+from osdf.utils.interfaces import json_from_file
+from unittest.mock import patch
+import osdf.config.loader as config_loader
+from osdf.utils.programming_utils import DotDict
+import unittest
+
+
+class TestSimpleRouteOptimization(unittest.TestCase):
+ @patch('apps.route.optimizers.simple_route_opt.requests.get')
+ @patch('apps.route.optimizers.simple_route_opt.pymzn.minizinc')
+ def test_process_nst_selection_solutions( self, mock_solve, mock_get):
+
+ main_dir = ""
+ response_data_file = main_dir + "test/simple_route_opt/AAI.json"
+ mock_get.return_value.json.return_value = json_from_file(response_data_file)
+ mock_get.return_value.status_code = 200
+ mock_solve.return_value = [{'x': [1, 1, 1]}]
+ self.config_spec = {
+ "deployment": "test/functest/simulators/simulated-config/osdf_config.yaml",
+ "core": "test/functest/simulators/simulated-config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+ parameter_data_file = main_dir + "test/simple_route_opt/routeOpt.json"
+ request_json = json_from_file(parameter_data_file)
+ mock_response = {
+ "requestId": "yyy-yyy-yyyy",
+ "requestStatus": "accepted",
+ "solutions": [
+ {
+ "end_node": "10.10.10.10",
+ "link": "link-id-1",
+ "start_node": "20.20.20.20"
+ },
+ {
+ "end_node": "11.11.11.11",
+ "link": "link-id-2",
+ "start_node": "22.22.22.22"
+ },
+ {
+ "end_node": "20.20.20.20",
+ "link": "link-id-3",
+ "start_node": "11.11.11.11"
+ }
+ ],
+ "statusMessage": " ",
+ "transactionId": "xxx-xxx-xxxx"
+ }
+ routopt = RouteOpt()
+ actual_response = routopt.get_route(request_json,self.osdf_config)
+ self.assertEqual(mock_response, actual_response)
+
+
+
+if __name__ == '__main__':
+ unittest.main()
+