summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/nxi_termination/__init__.py0
-rw-r--r--apps/nxi_termination/models/api/_init_.py0
-rw-r--r--apps/nxi_termination/models/api/nxi_termination_request.py45
-rw-r--r--apps/nxi_termination/optimizers/__init__.py0
-rw-r--r--apps/nxi_termination/optimizers/remote_opt_processor.py123
-rw-r--r--apps/nxi_termination/optimizers/response_processor.py45
-rwxr-xr-xconfig/osdf_config.yaml1
-rw-r--r--osdf/adapters/aai/_init_.py0
-rw-r--r--osdf/adapters/aai/fetch_aai_data.py55
-rwxr-xr-xosdfapp.py13
-rw-r--r--test/apps/nxi_termination/_init_.py0
-rw-r--r--test/apps/nxi_termination/aai_exception_response.json4
-rw-r--r--test/apps/nxi_termination/aai_response.json64
-rw-r--r--test/apps/nxi_termination/exception_response1.json7
-rw-r--r--test/apps/nxi_termination/failure_relationship_list.json27
-rw-r--r--test/apps/nxi_termination/failure_relationship_list2.json52
-rw-r--r--test/apps/nxi_termination/failure_service_profiles.json24
-rw-r--r--test/apps/nxi_termination/failure_service_profiles2.json42
-rw-r--r--test/apps/nxi_termination/invalid_request.json17
-rw-r--r--test/apps/nxi_termination/nsi_success_output.json7
-rw-r--r--test/apps/nxi_termination/nssi_failure_output.json8
-rw-r--r--test/apps/nxi_termination/nssi_termination.json17
-rw-r--r--test/apps/nxi_termination/nxi_failure_output1.json10
-rw-r--r--test/apps/nxi_termination/nxi_failure_output2.json7
-rw-r--r--test/apps/nxi_termination/nxi_termination.json17
-rw-r--r--test/apps/nxi_termination/service_profiles.json23
-rw-r--r--test/apps/nxi_termination/success_relationship_list.json27
-rw-r--r--test/apps/nxi_termination/test_fetch_aai_data.py70
-rw-r--r--test/apps/nxi_termination/test_remote_opt_processor_termination.py141
-rwxr-xr-xtest/config/osdf_config.yaml3
-rw-r--r--test/test_api_validation.py11
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))
diff --git a/osdfapp.py b/osdfapp.py
index eb99fac..9234d78 100755
--- a/osdfapp.py
+++ b/osdfapp.py
@@ -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):