diff options
31 files changed, 860 insertions, 0 deletions
diff --git a/apps/nxi_termination/__init__.py b/apps/nxi_termination/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/apps/nxi_termination/__init__.py diff --git a/apps/nxi_termination/models/api/_init_.py b/apps/nxi_termination/models/api/_init_.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/apps/nxi_termination/models/api/_init_.py diff --git a/apps/nxi_termination/models/api/nxi_termination_request.py b/apps/nxi_termination/models/api/nxi_termination_request.py new file mode 100644 index 0000000..45456cf --- /dev/null +++ b/apps/nxi_termination/models/api/nxi_termination_request.py @@ -0,0 +1,45 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +from osdf.models.api.common import OSDFModel +from schematics.types import BaseType +from schematics.types.compound import DictType +from schematics.types.compound import ModelType +from schematics.types import IntType +from schematics.types import StringType +from schematics.types import URLType + + +class RequestInfo(OSDFModel): + """Info for northbound request from client such as SO""" + transactionId = StringType(required=True) + requestId = StringType(required=True) + callbackUrl = URLType(required=True) + callbackHeader = DictType(BaseType) + sourceId = StringType(required=True) + timeout = IntType() + addtnlArgs = DictType(BaseType) + + +class NxiTerminationApi(OSDFModel): + """Request for nxi termination (specific to optimization and additional metadata""" + requestInfo = ModelType(RequestInfo, required=True) + type = StringType(required=True, choices=['NSI', 'NSSI']) + NxIId = StringType(required=True) + UUID = StringType() + invariantUUID = StringType() diff --git a/apps/nxi_termination/optimizers/__init__.py b/apps/nxi_termination/optimizers/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/apps/nxi_termination/optimizers/__init__.py diff --git a/apps/nxi_termination/optimizers/remote_opt_processor.py b/apps/nxi_termination/optimizers/remote_opt_processor.py new file mode 100644 index 0000000..8867c97 --- /dev/null +++ b/apps/nxi_termination/optimizers/remote_opt_processor.py @@ -0,0 +1,123 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# +from apps.nxi_termination.optimizers.response_processor import get_nxi_termination_failure_response +from apps.nxi_termination.optimizers.response_processor import get_nxi_termination_response +from osdf.adapters.aai.fetch_aai_data import AAIException +from osdf.adapters.aai.fetch_aai_data import get_aai_data + + +def process_nxi_termination_opt(request_json, osdf_config): + + """Process the nxi Termination request from API layer + + :param request_json: api request + :param osdf_config: configuration specific to OSDF app + :return: response as a success,failure + """ + + type = request_json["type"] + request_info = request_json.get("requestInfo", {}) + addtnl_args = request_info.get("addtnlArgs", {}) + if type == "NSI": + arg_val = addtnl_args.get("serviceProfileId", "") + return check_nxi_termination(request_json, osdf_config, addtnl_args, arg_val, + get_service_profiles, get_service_profile_id) + + else: + arg_val = addtnl_args.get("serviceInstanceId", "") + return check_nxi_termination(request_json, osdf_config, addtnl_args, arg_val, get_relationshiplist, get_nsi_id) + + +def check_nxi_termination(request_json, osdf_config, addtnl_args, arg_val, get_response_object, get_response_id): + request_info = request_json.get("requestInfo", {}) + + try: + response_object = get_response_object(request_json, osdf_config) + if addtnl_args and arg_val and len(response_object) == 1: + response_id = get_response_id(response_object) + if arg_val == response_id: + reason = '' + return set_success_response(reason, request_info, terminate_response=True) + + else: + reason = "{} is not available in AAI".format(arg_val) + return set_success_response(reason, request_info, terminate_response=False) + + elif len(response_object) == 0: + reason = '' + return set_success_response(reason, request_info, terminate_response=True) + + else: + reason = "Associated to more than one" + return set_success_response(reason, request_info, terminate_response=False) + + except AAIException as e: + reason = str(e) + return set_failure_response(reason, request_info) + + except Exception as e: + reason = "{} Exception Occurred while processing".format(str(e)) + return set_failure_response(reason, request_info) + + +def get_service_profiles(request_json, osdf_config): + try: + json_response = get_aai_data(request_json, osdf_config) + service_profiles = json_response.get("service-profiles", {}) + service_profile = service_profiles.get("service-profile", []) + return service_profile + except AAIException as e: + raise AAIException(e) + + +def get_relationshiplist(request_json, osdf_config): + try: + json_response = get_aai_data(request_json, osdf_config) + rel_list = json_response.get("relationship-list", {}) + relationship = rel_list.get("relationship", []) + return relationship + except AAIException as e: + raise AAIException(e) + + +def get_service_profile_id(service_profile): + profile_obj = service_profile[0] + return profile_obj.get("profile-id", "") + + +def get_nsi_id(relationship): + rel_obj = relationship[0] + rel_data = rel_obj.get("relationship-data", []) + for data in rel_data: + if data["relationship-key"] == "service-instance.service-instance-id": + return data["relationship-value"] + + +def set_success_response(reason, request_info, terminate_response): + res = dict() + res["requestStatus"] = "success" + res["terminateResponse"] = terminate_response + res["reason"] = reason + return get_nxi_termination_response(request_info, res) + + +def set_failure_response(reason, request_info,): + res = dict() + res["requestStatus"] = "failure" + res["reason"] = reason + return get_nxi_termination_failure_response(request_info, res) diff --git a/apps/nxi_termination/optimizers/response_processor.py b/apps/nxi_termination/optimizers/response_processor.py new file mode 100644 index 0000000..e7f1041 --- /dev/null +++ b/apps/nxi_termination/optimizers/response_processor.py @@ -0,0 +1,45 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +def get_nxi_termination_response(request_info, response): + + """Get NXI termination response from final solution + + :param request_info: request info + :param response: response to be send + :return: NxI Termination response to send back as dictionary + """ + return {'requestId': request_info['requestId'], + 'transactionId': request_info['transactionId'], + 'requestStatus': response["requestStatus"], + 'terminateResponse': response["terminateResponse"], + 'reason': response['reason']} + + +def get_nxi_termination_failure_response(request_info, response): + + """Get NXI termination response from final solution + + :param request_info: request info + :param response: response to be send + :return: NxI Termination response to send back as dictionary + """ + return {'requestId': request_info['requestId'], + 'transactionId': request_info['transactionId'], + 'requestStatus': response["requestStatus"], + 'reason': response['reason']} diff --git a/config/osdf_config.yaml b/config/osdf_config.yaml index 19f5574..4207b34 100755 --- a/config/osdf_config.yaml +++ b/config/osdf_config.yaml @@ -53,6 +53,7 @@ configDbGetNbrListUrl: 'SDNCConfigDBAPI/getNbrList' #aai api aaiUrl: "https://aai.url:30233" aaiGetLinksUrl: "/aai/v16/network/logical-links" +aaiServiceInstanceUrl : "/aai/v20/nodes/service-instances/service-instance/" aaiGetControllersUrl: /aai/v19/external-system/esr-thirdparty-sdnc-list controllerQueryUrl: /aai/v19/query?format=resource aaiGetInterDomainLinksUrl: /aai/v19/network/logical-links?link-type=inter-domain&operational-status=up diff --git a/osdf/adapters/aai/_init_.py b/osdf/adapters/aai/_init_.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/osdf/adapters/aai/_init_.py diff --git a/osdf/adapters/aai/fetch_aai_data.py b/osdf/adapters/aai/fetch_aai_data.py new file mode 100644 index 0000000..634aa04 --- /dev/null +++ b/osdf/adapters/aai/fetch_aai_data.py @@ -0,0 +1,55 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +import requests +from requests.auth import HTTPBasicAuth +from requests import RequestException + + +class AAIException(Exception): + pass + + +def get_aai_data(request_json, osdf_config): + + """Get the response from AAI + + :param request_json: requestjson + :param osdf_config: configuration specific to OSDF app + :return:response body from AAI + """ + aai_headers = { + "X-TransactionId": "9999", + "X-FromAppId": "OOF", + "Accept": "application/json", + "Content-Type": "application/json", + } + nxi_id = request_json["NxIId"] + config = osdf_config.deployment + aai_url = config["aaiUrl"] + aai_req_url = aai_url + config["aaiServiceInstanceUrl"] + nxi_id + "?depth=2" + + try: + response = requests.get(aai_req_url, aai_headers, auth=HTTPBasicAuth("AAI", "AAI"), verify=False) + except RequestException as e: + raise AAIException("Request exception was encountered {}".format(e)) + + if response.status_code == 200: + return response.json() + else: + raise AAIException("Error response recieved from AAI for the request {}".format(aai_req_url)) @@ -1,5 +1,6 @@ # ------------------------------------------------------------------------- # Copyright (c) 2015-2017 AT&T Intellectual Property +# Copyright (C) 2020 Wipro Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -44,6 +45,8 @@ from osdf.logging.osdf_logging import MH, audit_log from osdf.operation.responses import osdf_response_for_request_accept as req_accept from osdf.utils import api_data_utils from osdf.webapp.appcontroller import auth_basic +from apps.nxi_termination.optimizers.remote_opt_processor import process_nxi_termination_opt +from apps.nxi_termination.models.api.nxi_termination_request import NxiTerminationApi @app.route("/api/oof/v1/healthcheck", methods=["GET"]) @@ -105,6 +108,7 @@ def do_route_calc(): response = RouteOpt().get_route(request_json, osdf_config) return response + @app.route("/api/oof/mdons/route/v1", methods=["POST"]) def do_mdons_route_calc(): """ @@ -115,6 +119,7 @@ def do_mdons_route_calc(): response = InterDomainRouteOpt().get_route(request_json, osdf_config) return response + @app.route("/api/oof/v1/selection/nst", methods=["POST"]) def do_nst_selection(): request_json = request.get_json() @@ -179,6 +184,14 @@ def do_nssi_selection(): transaction_id=request_json['requestInfo']['transactionId'], request_status="accepted", status_message="") +@app.route("/api/oof/terminate/nxi/v1",methods=["POST"]) +def do_nxi_terminaton(): + request_json = request.get_json() + req_id = request_json['requestInfo']['requestId'] + g.request_id = req_id + audit_log.info(MH.received_request(request.url, request.remote_addr, json.dumps(request_json))) + NxiTerminationApi(request_json).validate() + return process_nxi_termination_opt(request_json,osdf_config) if __name__ == "__main__": run_app() diff --git a/test/apps/nxi_termination/_init_.py b/test/apps/nxi_termination/_init_.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/apps/nxi_termination/_init_.py diff --git a/test/apps/nxi_termination/aai_exception_response.json b/test/apps/nxi_termination/aai_exception_response.json new file mode 100644 index 0000000..56f61df --- /dev/null +++ b/test/apps/nxi_termination/aai_exception_response.json @@ -0,0 +1,4 @@ +{ + "status-code": 404, + "status-response": "NOT FOUND" +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/aai_response.json b/test/apps/nxi_termination/aai_response.json new file mode 100644 index 0000000..b7ef43b --- /dev/null +++ b/test/apps/nxi_termination/aai_response.json @@ -0,0 +1,64 @@ +{"service-instance": [{ + "service-instance-id": "1a636c4d-5e76-427e-bfd6-241a947224b0", + "service-instance-name": "nssi_test_0211", + "service-type": "embb", + "service-role": "nssi", + "environment-context": "cn", + "model-invariant-id": "21d57d4b-52ad-4d3c-a798-248b5bb9124a", + "model-version-id": "bfba363e-e39c-4bd9-a9d5-1371c28f4d22", + "resource-version": "1581418601616", + "orchestration-status": "active", + "relationship-list": { + "relationship": [ + { + "related-to": "service-instance", + "relationship-label": "org.onap.relationships.inventory.ComposedOf", + "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518", + "relationship-data": [ + { + "relationship-key": "customer.global-customer-id", + "relationship-value": "5GCustomer" + }, + { + "relationship-key": "service-subscription.service-type", + "relationship-value": "5G" + }, + { + "relationship-key": "service-instance.service-instance-id", + "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b518" + } + ], + "related-to-property": [ + { + "property-key": "service-instance.service-instance-name", + "property-value": "nsi_test_0211" + } + ] + } + ] + }, + "slice-profiles": { + "slice-profile": [ + { + "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c299", + "latency": 20, + "max-number-of-UEs": 0, + "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]", + "ue-mobility-level": "stationary", + "resource-sharing-level": "0", + "exp-data-rate-UL": 100, + "exp-data-rate-DL": 100, + "activity-factor": 0, + "e2e-latency": 0, + "jitter": 0, + "survival-time": 0, + "exp-data-rate": 0, + "payload-size": 0, + "traffic-density": 0, + "conn-density": 0, + "reliability": 99.999, + "resource-version": "1581418602494" + } + ] + } +}]} diff --git a/test/apps/nxi_termination/exception_response1.json b/test/apps/nxi_termination/exception_response1.json new file mode 100644 index 0000000..cde603f --- /dev/null +++ b/test/apps/nxi_termination/exception_response1.json @@ -0,0 +1,7 @@ +{ + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestStatus": "failure", + "reason": "Error response recieved from AAI for the request" + +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/failure_relationship_list.json b/test/apps/nxi_termination/failure_relationship_list.json new file mode 100644 index 0000000..537f283 --- /dev/null +++ b/test/apps/nxi_termination/failure_relationship_list.json @@ -0,0 +1,27 @@ +[ + { + "related-to": "service-instance", + "relationship-label": "org.onap.relationships.inventory.ComposedOf", + "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518", + "relationship-data": [ + { + "relationship-key": "customer.global-customer-id", + "relationship-value": "5GCustomer" + }, + { + "relationship-key": "service-subscription.service-type", + "relationship-value": "5G" + }, + { + "relationship-key": "service-instance.service-instance-id", + "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b567" + } + ], + "related-to-property": [ + { + "property-key": "service-instance.service-instance-name", + "property-value": "nsi_test_0211" + } + ] + } + ]
\ No newline at end of file diff --git a/test/apps/nxi_termination/failure_relationship_list2.json b/test/apps/nxi_termination/failure_relationship_list2.json new file mode 100644 index 0000000..624448a --- /dev/null +++ b/test/apps/nxi_termination/failure_relationship_list2.json @@ -0,0 +1,52 @@ +[ + { + "related-to": "service-instance", + "relationship-label": "org.onap.relationships.inventory.ComposedOf", + "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518", + "relationship-data": [ + { + "relationship-key": "customer.global-customer-id", + "relationship-value": "5GCustomer" + }, + { + "relationship-key": "service-subscription.service-type", + "relationship-value": "5G" + }, + { + "relationship-key": "service-instance.service-instance-id", + "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b567" + } + ], + "related-to-property": [ + { + "property-key": "service-instance.service-instance-name", + "property-value": "nsi_test_0211" + } + ] + }, + { + "related-to": "service-instance", + "relationship-label": "org.onap.relationships.inventory.ComposedOf", + "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518", + "relationship-data": [ + { + "relationship-key": "customer.global-customer-id", + "relationship-value": "5GCustomer" + }, + { + "relationship-key": "service-subscription.service-type", + "relationship-value": "5G" + }, + { + "relationship-key": "service-instance.service-instance-id", + "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b567" + } + ], + "related-to-property": [ + { + "property-key": "service-instance.service-instance-name", + "property-value": "nsi_test_0211" + } + ] + } + ]
\ No newline at end of file diff --git a/test/apps/nxi_termination/failure_service_profiles.json b/test/apps/nxi_termination/failure_service_profiles.json new file mode 100644 index 0000000..d10a818 --- /dev/null +++ b/test/apps/nxi_termination/failure_service_profiles.json @@ -0,0 +1,24 @@ +[ + { + "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c29", + "latency": 20, + "max-number-of-UEs": 0, + "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]", + "ue-mobility-level": "stationary", + "resource-sharing-level": "0", + "exp-data-rate-UL": 100, + "exp-data-rate-DL": 100, + "activity-factor": 0, + "e2e-latency": 0, + "jitter": 0, + "survival-time": 0, + "exp-data-rate": 0, + "payload-size": 0, + "traffic-density": 0, + "conn-density": 0, + "reliability": 99.999, + "resource-version": "1581418602494" + } +] + + diff --git a/test/apps/nxi_termination/failure_service_profiles2.json b/test/apps/nxi_termination/failure_service_profiles2.json new file mode 100644 index 0000000..1740758 --- /dev/null +++ b/test/apps/nxi_termination/failure_service_profiles2.json @@ -0,0 +1,42 @@ +[ + { + "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c299", + "latency": 20, + "max-number-of-UEs": 0, + "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]", + "ue-mobility-level": "stationary", + "resource-sharing-level": "0", + "exp-data-rate-UL": 100, + "exp-data-rate-DL": 100, + "activity-factor": 0, + "e2e-latency": 0, + "jitter": 0, + "survival-time": 0, + "exp-data-rate": 0, + "payload-size": 0, + "traffic-density": 0, + "conn-density": 0, + "reliability": 99.999, + "resource-version": "1581418602494" + }, + { + "profile-id": "abcd9f49-4201-4e3a-aac1-b0f27902c299", + "latency": 20, + "max-number-of-UEs": 0, + "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]", + "ue-mobility-level": "stationary", + "resource-sharing-level": "0", + "exp-data-rate-UL": 100, + "exp-data-rate-DL": 100, + "activity-factor": 0, + "e2e-latency": 0, + "jitter": 0, + "survival-time": 0, + "exp-data-rate": 0, + "payload-size": 0, + "traffic-density": 0, + "conn-density": 0, + "reliability": 99.999, + "resource-version": "1581418602494" + } +] diff --git a/test/apps/nxi_termination/invalid_request.json b/test/apps/nxi_termination/invalid_request.json new file mode 100644 index 0000000..793776d --- /dev/null +++ b/test/apps/nxi_termination/invalid_request.json @@ -0,0 +1,17 @@ +{ + "requestInfo": { + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "callbackUrl": "http://0.0.0.0:9000/osdfCallback/", + "sourceId": "SO", + "timeout": 5, + "addtnlArgs": { + "serviceProfileId":"cdad9f49-4201-4e3a-aac1-b0f27902c299" + } + }, + "type":"NST", + "NxIId":"d290f1ee-6c54-4b01-90e6-d701748f0851", + "UUID":"d290f1ee-6c54-4b01-90e6-d701748f0851", + "invariantUUID":"d290f1ee-6c54-4b01-90e6-d701748f0851" + +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/nsi_success_output.json b/test/apps/nxi_termination/nsi_success_output.json new file mode 100644 index 0000000..e25a272 --- /dev/null +++ b/test/apps/nxi_termination/nsi_success_output.json @@ -0,0 +1,7 @@ +{ + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestStatus": "success", + "terminateResponse": true, + "reason": "" +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/nssi_failure_output.json b/test/apps/nxi_termination/nssi_failure_output.json new file mode 100644 index 0000000..5ada892 --- /dev/null +++ b/test/apps/nxi_termination/nssi_failure_output.json @@ -0,0 +1,8 @@ +{ + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestStatus": "success", + "terminateResponse": false, + "reason": "4115d3c8-dd59-45d6-b09d-e756dee9b518 is not available in AAI" + +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/nssi_termination.json b/test/apps/nxi_termination/nssi_termination.json new file mode 100644 index 0000000..b4e3711 --- /dev/null +++ b/test/apps/nxi_termination/nssi_termination.json @@ -0,0 +1,17 @@ +{ + "requestInfo": { + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "callbackUrl": "http://0.0.0.0:9000/osdfCallback/", + "sourceId": "SO", + "timeout": 5, + "addtnlArgs": { + "serviceInstanceId":"4115d3c8-dd59-45d6-b09d-e756dee9b518" + } + }, + "type":"NSSI", + "NxIId":"d290f1ee-6c54-4b01-90e6-d701748f0851", + "UUID":"d290f1ee-6c54-4b01-90e6-d701748f0851", + "invariantUUID":"d290f1ee-6c54-4b01-90e6-d701748f0851" + +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/nxi_failure_output1.json b/test/apps/nxi_termination/nxi_failure_output1.json new file mode 100644 index 0000000..b363e86 --- /dev/null +++ b/test/apps/nxi_termination/nxi_failure_output1.json @@ -0,0 +1,10 @@ +{ + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestStatus": "success", + "terminateResponse": false, + "reason": "cdad9f49-4201-4e3a-aac1-b0f27902c299 is not available in AAI" + +} + + diff --git a/test/apps/nxi_termination/nxi_failure_output2.json b/test/apps/nxi_termination/nxi_failure_output2.json new file mode 100644 index 0000000..5d430bc --- /dev/null +++ b/test/apps/nxi_termination/nxi_failure_output2.json @@ -0,0 +1,7 @@ +{ + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestStatus": "success", + "terminateResponse": false, + "reason": "Associated to more than one" +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/nxi_termination.json b/test/apps/nxi_termination/nxi_termination.json new file mode 100644 index 0000000..ac53c4d --- /dev/null +++ b/test/apps/nxi_termination/nxi_termination.json @@ -0,0 +1,17 @@ +{ + "requestInfo": { + "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "callbackUrl": "http://0.0.0.0:9000/osdfCallback/", + "sourceId": "SO", + "timeout": 5, + "addtnlArgs": { + "serviceProfileId":"cdad9f49-4201-4e3a-aac1-b0f27902c299" + } + }, + "type":"NSI", + "NxIId":"d290f1ee-6c54-4b01-90e6-d701748f0851", + "UUID":"d290f1ee-6c54-4b01-90e6-d701748f0851", + "invariantUUID":"d290f1ee-6c54-4b01-90e6-d701748f0851" + +}
\ No newline at end of file diff --git a/test/apps/nxi_termination/service_profiles.json b/test/apps/nxi_termination/service_profiles.json new file mode 100644 index 0000000..899acb4 --- /dev/null +++ b/test/apps/nxi_termination/service_profiles.json @@ -0,0 +1,23 @@ +[ + { + "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c299", + "latency": 20, + "max-number-of-UEs": 0, + "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]", + "ue-mobility-level": "stationary", + "resource-sharing-level": "0", + "exp-data-rate-UL": 100, + "exp-data-rate-DL": 100, + "activity-factor": 0, + "e2e-latency": 0, + "jitter": 0, + "survival-time": 0, + "exp-data-rate": 0, + "payload-size": 0, + "traffic-density": 0, + "conn-density": 0, + "reliability": 99.999, + "resource-version": "1581418602494" + } +] + diff --git a/test/apps/nxi_termination/success_relationship_list.json b/test/apps/nxi_termination/success_relationship_list.json new file mode 100644 index 0000000..4f2a8bb --- /dev/null +++ b/test/apps/nxi_termination/success_relationship_list.json @@ -0,0 +1,27 @@ +[ + { + "related-to": "service-instance", + "relationship-label": "org.onap.relationships.inventory.ComposedOf", + "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518", + "relationship-data": [ + { + "relationship-key": "customer.global-customer-id", + "relationship-value": "5GCustomer" + }, + { + "relationship-key": "service-subscription.service-type", + "relationship-value": "5G" + }, + { + "relationship-key": "service-instance.service-instance-id", + "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b518" + } + ], + "related-to-property": [ + { + "property-key": "service-instance.service-instance-name", + "property-value": "nsi_test_0211" + } + ] + } + ]
\ No newline at end of file diff --git a/test/apps/nxi_termination/test_fetch_aai_data.py b/test/apps/nxi_termination/test_fetch_aai_data.py new file mode 100644 index 0000000..241b24b --- /dev/null +++ b/test/apps/nxi_termination/test_fetch_aai_data.py @@ -0,0 +1,70 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +import unittest +import mock +from unittest.mock import patch +from osdf.config.base import osdf_config +import osdf.config.loader as config_loader +from osdf.utils.programming_utils import DotDict +from osdf.utils.interfaces import json_from_file +from osdf.adapters.aai.fetch_aai_data import get_aai_data,AAIException + +class TestRemoteOptProcessor(unittest.TestCase): + def setUp(self): + self.config_spec = { + "deployment": "config/osdf_config.yaml", + "core": "config/common_config.yaml" + } + self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec)) + + def tearDown(self): + + patch.stopall() + + + def test_get_aai_data(self): + main_dir = "" + response_file = main_dir + 'test/apps/nxi_termination/aai_response.json' + exception_response_file = main_dir + 'test/apps/nxi_termination/aai_exception_response.json' + request_file = main_dir + 'test/apps/nxi_termination/nxi_termination.json' + response_json = json_from_file(response_file) + request_json = json_from_file(request_file) + exception_json = json_from_file(exception_response_file) + response = mock.MagicMock() + response.status_code = 200 + response.ok = True + response.json.return_value = response_json + self.patcher_req = patch('requests.get', + return_value = response) + self.Mock_req = self.patcher_req.start() + self.assertEquals(response_json, get_aai_data(request_json,osdf_config)) + self.patcher_req.stop() + + responsenew=mock.MagicMock() + responsenew.status_code=404 + responsenew.json.return_value = exception_json + self.patcher_req = patch('requests.get', + return_value=responsenew) + self.Mock_req = self.patcher_req.start() + self.assertRaises( AAIException,get_aai_data,request_json,osdf_config) + self.patcher_req.stop() + + +if __name__ == "__main__": + unittest.main()
\ No newline at end of file diff --git a/test/apps/nxi_termination/test_remote_opt_processor_termination.py b/test/apps/nxi_termination/test_remote_opt_processor_termination.py new file mode 100644 index 0000000..4fa8170 --- /dev/null +++ b/test/apps/nxi_termination/test_remote_opt_processor_termination.py @@ -0,0 +1,141 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2020 Wipro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------- +# + +import unittest +from unittest.mock import patch +import osdf.config.loader as config_loader +import pytest +from apps.nxi_termination.optimizers.remote_opt_processor import process_nxi_termination_opt +from osdf.adapters.aai.fetch_aai_data import AAIException + +from osdf.config.base import osdf_config +from osdf.utils.programming_utils import DotDict +from osdf.utils.interfaces import json_from_file + +class TestRemoteOptProcessor(unittest.TestCase): + def setUp(self): + self.config_spec = { + "deployment": "config/osdf_config.yaml", + "core": "config/common_config.yaml" + } + self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec)) + + def tearDown(self): + + patch.stopall() + + def test_process_nxi_termination_opt(self): + main_dir = "" + request_file = main_dir + 'test/apps/nxi_termination/nxi_termination.json' + nssi_request_file=main_dir + 'test/apps/nxi_termination/nssi_termination.json' + service_file = main_dir + 'test/apps/nxi_termination/service_profiles.json' + failure_service_file = main_dir + 'test/apps/nxi_termination/failure_service_profiles.json' + failure_service_file2 = main_dir + 'test/apps/nxi_termination/failure_service_profiles2.json' + nsi_success=main_dir + 'test/apps/nxi_termination/nsi_success_output.json' + nxi_failure1 = main_dir + 'test/apps/nxi_termination/nxi_failure_output1.json' + nxi_failure2 = main_dir + 'test/apps/nxi_termination/nxi_failure_output2.json' + nssi_failure = main_dir + 'test/apps/nxi_termination/nssi_failure_output.json' + success_rel_file = main_dir + 'test/apps/nxi_termination/success_relationship_list.json' + failure_rel_file1 = main_dir + 'test/apps/nxi_termination/failure_relationship_list.json' + failure_rel_file2 = main_dir + 'test/apps/nxi_termination/failure_relationship_list2.json' + exception_response_file1 = main_dir + 'test/apps/nxi_termination/exception_response1.json' + request_json=json_from_file(request_file) + nssi_request_json = json_from_file(nssi_request_file) + service_profile_json = json_from_file(service_file) + failure_service_profile_json = json_from_file(failure_service_file) + failure_service_profile_json2 = json_from_file(failure_service_file2) + success_rel_json=json_from_file(success_rel_file) + failure_rel_json = json_from_file(failure_rel_file1) + failure_rel_json2 = json_from_file(failure_rel_file2) + success_output_json=json_from_file(nsi_success) + nxi_failure_output_json1 = json_from_file(nxi_failure1) + nxi_failure_output_json2 = json_from_file(nxi_failure2) + nssi_failure_output_json = json_from_file(nssi_failure) + exception_response_json1 = json_from_file(exception_response_file1) + + #nsi success scenario + self.patcher_req=patch('apps.nxi_termination.optimizers.remote_opt_processor.get_service_profiles',return_value=service_profile_json) + self.Mock_req = self.patcher_req.start() + self.assertEquals(success_output_json, process_nxi_termination_opt(request_json,osdf_config)) + self.patcher_req.stop() + + #nsi failure scenario + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_service_profiles', return_value=failure_service_profile_json) + self.Mock_req = self.patcher_req.start() + self.assertEquals(nxi_failure_output_json1, process_nxi_termination_opt(request_json, osdf_config)) + self.patcher_req.stop() + + #nsi success scenario + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_service_profiles', + return_value=[]) + self.Mock_req = self.patcher_req.start() + self.assertEquals(success_output_json, process_nxi_termination_opt(request_json, osdf_config)) + self.patcher_req.stop() + + # nsi failure scenario + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_service_profiles', + return_value=failure_service_profile_json2) + self.Mock_req = self.patcher_req.start() + self.assertEquals(nxi_failure_output_json2, process_nxi_termination_opt(request_json, osdf_config)) + self.patcher_req.stop() + # # + # nssi success scenario + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_relationshiplist', return_value=success_rel_json) + self.Mock_req = self.patcher_req.start() + self.assertEquals(success_output_json, process_nxi_termination_opt(nssi_request_json, osdf_config)) + self.patcher_req.stop() + + # nssi success scenario + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_relationshiplist', + return_value=[]) + self.Mock_req = self.patcher_req.start() + self.assertEquals(success_output_json, process_nxi_termination_opt(nssi_request_json, osdf_config)) + self.patcher_req.stop() + + # nssi failure scenario + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_relationshiplist', + return_value=failure_rel_json) + self.Mock_req = self.patcher_req.start() + self.assertEquals(nssi_failure_output_json, process_nxi_termination_opt(nssi_request_json, osdf_config)) + self.patcher_req.stop() + + # nssi failure scenario + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_relationshiplist', + return_value=failure_rel_json2) + self.Mock_req = self.patcher_req.start() + self.assertEquals(nxi_failure_output_json2, process_nxi_termination_opt(nssi_request_json, osdf_config)) + self.patcher_req.stop() + + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_relationshiplist', + side_effect=AAIException("Error response recieved from AAI for the request")) + self.Mock_req = self.patcher_req.start() + self.assertEquals(exception_response_json1, process_nxi_termination_opt(nssi_request_json, osdf_config)) + self.patcher_req.stop() + + + self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_relationshiplist', + side_effect=AAIException("Request exception was encountered")) + self.Mock_req = self.patcher_req.start() + self.assertEquals("failure", process_nxi_termination_opt(nssi_request_json, osdf_config).get('requestStatus')) + self.patcher_req.stop() + + + + +if __name__ == "__main__": + unittest.main()
\ No newline at end of file diff --git a/test/config/osdf_config.yaml b/test/config/osdf_config.yaml index eaa31ff..2ed8b88 100755 --- a/test/config/osdf_config.yaml +++ b/test/config/osdf_config.yaml @@ -67,3 +67,6 @@ pciHMSPassword: "" # pcihandler password for call back. # Credentials for the OOF PCI Opt service osdfPCIOptUsername: PCI-OSDF-USER osdfPCIOptPassword: PCI-OSDF-PASSWD + +aaiUrl: "https://aai.url:30233" +aaiServiceInstanceUrl : "/aai/v20/nodes/service-instances/service-instance/" diff --git a/test/test_api_validation.py b/test/test_api_validation.py index 37f1321..3a20262 100644 --- a/test/test_api_validation.py +++ b/test/test_api_validation.py @@ -24,6 +24,7 @@ from apps.placement.models.api.placementRequest import PlacementAPI from apps.placement.models.api.placementResponse import PlacementResponse from apps.slice_selection.models.api.nsi_selection_request import NSISelectionAPI from apps.slice_selection.models.api.nssi_selection_request import NSSISelectionAPI +from apps.nxi_termination.models.api.nxi_termination_request import NxiTerminationApi class TestReqValidation(unittest.TestCase): @@ -62,6 +63,16 @@ class TestReqValidation(unittest.TestCase): req_json = {} self.assertRaises(DataError, lambda: PlacementAPI(req_json).validate()) + def test_req_nxi_validation(self): + req_file = "./test/apps/nxi_termination/nxi_termination.json" + req_json = json.loads(open(req_file).read()) + self.assertEqual(NxiTerminationApi(req_json).validate(), None) + + def test_req_invalid_nxi(self): + req_file = "./test/apps/nxi_termination/invalid_request.json" + req_json = json.loads(open(req_file).read()) + self.assertRaises(DataError, lambda: NxiTerminationApi(req_json).validate()) + class TestResponseValidation(unittest.TestCase): |