summaryrefslogtreecommitdiffstats
path: root/mock-so
diff options
context:
space:
mode:
authorMichal Jagiello <michal.jagiello@t-mobile.pl>2023-03-13 11:00:21 +0000
committerMichal Jagiello <michal.jagiello@t-mobile.pl>2023-03-14 14:25:16 +0000
commit870ff702088b89549bc21631eb48443fff0bcd71 (patch)
tree5d52aca25035644bdc2ac687275ed858ba524e7e /mock-so
parent98e0e65ba145ab4c85c301118d4a0d02940221ec (diff)
Migrate mock applications from Orange GitLab
Move from Orange repositories into ONAP one. Issue-ID: INT-2208 Signed-off-by: Michal Jagiello <michal.jagiello@t-mobile.pl> Change-Id: I6e165da5144c28a6ff151e02e32f5ae89ce124e3
Diffstat (limited to 'mock-so')
-rw-r--r--mock-so/Dockerfile11
-rw-r--r--mock-so/README.md2
-rw-r--r--mock-so/app.py126
-rw-r--r--mock-so/requirements.txt2
-rw-r--r--mock-so/resources/__init__.py16
-rw-r--r--mock-so/resources/orchestration_request.py93
-rw-r--r--mock-so/resources/service_instance.py344
7 files changed, 594 insertions, 0 deletions
diff --git a/mock-so/Dockerfile b/mock-so/Dockerfile
new file mode 100644
index 0000000..d558a0d
--- /dev/null
+++ b/mock-so/Dockerfile
@@ -0,0 +1,11 @@
+FROM python:3.8-alpine
+
+COPY . /app
+
+WORKDIR /app
+
+RUN pip install -r requirements.txt
+
+ENTRYPOINT ["python"]
+
+CMD ["app.py"]
diff --git a/mock-so/README.md b/mock-so/README.md
new file mode 100644
index 0000000..539b890
--- /dev/null
+++ b/mock-so/README.md
@@ -0,0 +1,2 @@
+# mock-so
+
diff --git a/mock-so/app.py b/mock-so/app.py
new file mode 100644
index 0000000..b1d6db2
--- /dev/null
+++ b/mock-so/app.py
@@ -0,0 +1,126 @@
+"""SO mock application."""
+"""
+ Copyright 2023 Deutsche Telekom AG, Orange
+
+ 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 json
+
+from flask import Flask, request
+from flask_restful import Api
+
+from resources.orchestration_request import OrchestrationRequest
+from resources.service_instance import (
+ NetworkInstance,
+ NetworkInstanceList,
+ ServiceInstance,
+ ServiceInstanceList,
+ VnfInstance,
+ VnfInstanceList,
+ VfModuleInstance,
+ VfModuleInstanceList,
+)
+
+
+app = Flask(__name__)
+api = Api(app)
+
+
+@app.route("/reset")
+def reset():
+ """Reset endpoint.
+
+ Reset all resources.
+
+ Returns:
+ str: Empty string, it has to returns anything
+
+ """
+ ServiceInstanceList.reset()
+ OrchestrationRequest.reset()
+ return ""
+
+
+@app.route("/set_aai_mock", methods=["POST"])
+def set_aai_mock():
+ """Set A&AI mock url address.
+
+ Set it for all resources which connects with A&AI mock.
+
+ Returns:
+ str: Empty string, it has to returns anything
+
+ """
+ aai_mock_url = json.loads(request.data)["AAI_MOCK"]
+ ServiceInstance.set_aai_mock(aai_mock_url)
+ ServiceInstanceList.set_aai_mock(aai_mock_url)
+ VnfInstance.set_aai_mock(aai_mock_url)
+ VfModuleInstance.set_aai_mock(aai_mock_url)
+ VnfInstanceList.set_aai_mock(aai_mock_url)
+ VfModuleInstanceList.set_aai_mock(aai_mock_url)
+ NetworkInstance.set_aai_mock(aai_mock_url)
+ NetworkInstanceList.set_aai_mock(aai_mock_url)
+ return ""
+
+
+api.add_resource(
+ ServiceInstance,
+ "/onap/so/infra/serviceInstantiation/v7/serviceInstances/<service_instance_id>",
+)
+api.add_resource(
+ ServiceInstanceList, "/onap/so/infra/serviceInstantiation/v7/serviceInstances"
+)
+api.add_resource(
+ VnfInstance,
+ (
+ "/onap/so/infra/serviceInstantiation/v7/serviceInstances/<service_instance_id>/"
+ "vnfs/<vnf_instance_id>"
+ ),
+)
+api.add_resource(
+ VnfInstanceList,
+ "/onap/so/infra/serviceInstantiation/v7/serviceInstances/<service_instance_id>/vnfs",
+)
+api.add_resource(
+ VfModuleInstance,
+ (
+ "/onap/so/infra/serviceInstantiation/v7/serviceInstances/<service_instance_id>/vnfs/"
+ "<vnf_instance_id>/vfModules/<vf_module_instance_id>"
+ ),
+)
+api.add_resource(
+ VfModuleInstanceList,
+ (
+ "/onap/so/infra/serviceInstantiation/v7/serviceInstances/<service_instance_id>/vnfs/"
+ "<vnf_instance_id>/vfModules"
+ ),
+)
+api.add_resource(
+ OrchestrationRequest,
+ "/onap/so/infra/orchestrationRequests/v7/<orchestration_request_id>",
+)
+api.add_resource(
+ NetworkInstanceList,
+ "/onap/so/infra/serviceInstantiation/v7/serviceInstances/<service_instance_id>/networks",
+)
+api.add_resource(
+ NetworkInstance,
+ (
+ "/onap/so/infra/serviceInstantiation/v7/serviceInstances/<service_instance_id>/"
+ "networks/<network_instance_id>"
+ ),
+)
+
+
+if __name__ == "__main__":
+ app.run(host="0.0.0.0", debug=True)
diff --git a/mock-so/requirements.txt b/mock-so/requirements.txt
new file mode 100644
index 0000000..f733aba
--- /dev/null
+++ b/mock-so/requirements.txt
@@ -0,0 +1,2 @@
+Flask-RESTful==0.3.8
+requests==2.23.0 \ No newline at end of file
diff --git a/mock-so/resources/__init__.py b/mock-so/resources/__init__.py
new file mode 100644
index 0000000..e189131
--- /dev/null
+++ b/mock-so/resources/__init__.py
@@ -0,0 +1,16 @@
+"""SO mock resources."""
+"""
+ Copyright 2023 Deutsche Telekom AG, Orange
+
+ 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.
+"""
diff --git a/mock-so/resources/orchestration_request.py b/mock-so/resources/orchestration_request.py
new file mode 100644
index 0000000..e7df8e9
--- /dev/null
+++ b/mock-so/resources/orchestration_request.py
@@ -0,0 +1,93 @@
+"""Mock SO orchestration request resource."""
+"""
+ Copyright 2023 Deutsche Telekom AG, Orange
+
+ 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 dataclasses import dataclass, field
+from datetime import datetime
+from typing import Dict
+
+from flask_restful import Resource
+
+
+@dataclass
+class OrchestrationRequestData:
+ """Orchestration request dataclass."""
+
+ request_id: str
+ created_at: datetime = field(default_factory=datetime.now)
+
+
+ORCHESTRATION_REQUESTS = {}
+
+
+def time_diff(dt: datetime, diff: int = 1) -> bool:
+ """Check if given datetime has older (in seconds) than current datetime.
+
+ Args:
+ dt (datetime): Datetime to check
+ diff (int, optional): Number of seconds to check. Defaults to 1.
+
+ Returns:
+ bool: True if datetime is older, False otherwise
+
+ """
+ return (datetime.now() - dt).seconds > diff
+
+
+class OrchestrationRequest(Resource):
+ """Orchestration request resource."""
+
+ @staticmethod
+ def reset() -> None:
+ """Reset orchestration request resource.
+
+ Clean ORCHESTRATION_REQUESTS dictionary
+
+ """
+ global ORCHESTRATION_REQUESTS
+ ORCHESTRATION_REQUESTS = {}
+
+ def get(self, orchestration_request_id: str) -> Dict[str, Dict[str, str]]:
+ """Get orchestration request data.
+
+ Return orchestration request data from ORCHESTRATION_REQUESTS dictionary.
+ If it doesn't exist it creates that.
+
+ Args:
+ orchestration_request_id (str): Orchestration request id key value
+
+ Returns:
+ Dict[str, Dict[str, str]]: Orchestration request data
+ """
+ try:
+ orchestration_request_data = ORCHESTRATION_REQUESTS[
+ orchestration_request_id
+ ]
+ except KeyError:
+ orchestration_request_data = OrchestrationRequestData(
+ request_id=orchestration_request_id
+ )
+ ORCHESTRATION_REQUESTS[
+ orchestration_request_id
+ ] = orchestration_request_data
+ return {
+ "request": {
+ "requestStatus": {
+ "requestState": "COMPLETE"
+ if time_diff(orchestration_request_data.created_at)
+ else "IN_PROGRESS"
+ }
+ }
+ }
diff --git a/mock-so/resources/service_instance.py b/mock-so/resources/service_instance.py
new file mode 100644
index 0000000..60880c2
--- /dev/null
+++ b/mock-so/resources/service_instance.py
@@ -0,0 +1,344 @@
+"""SO mock instance resources."""
+"""
+ Copyright 2023 Deutsche Telekom AG, Orange
+
+ 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 typing import Callable, Dict, List
+from uuid import uuid4
+
+import requests
+from flask_restful import Resource, request
+
+
+SERVICE_INSTANCES = {}
+
+
+class SoResource(Resource):
+ """Base SO resource class."""
+
+ AAI_MOCK_URL = ""
+
+ @classmethod
+ def set_aai_mock(cls, aai_mock_url: str) -> None:
+ """Set A&AI mock address.
+
+ Instance resources needs to communicate with A&AI mock
+ to update it's state.
+
+ Args:
+ aai_mock_url (str): A&AI mock url
+
+ """
+ cls.AAI_MOCK_URL = aai_mock_url
+
+ @classmethod
+ def reset(cls) -> None:
+ """Reset SO resource.
+
+ Clean SERVICE_INSTANCES dictionary
+ and A&AI mock url address.
+
+ """
+ global SERVICE_INSTANCES
+ SERVICE_INSTANCES = {}
+ cls.AAI_MOCK_URL = ""
+
+ def check_aai_mock_address(method: Callable) -> Callable:
+ """Decorate method to check if A&AI address is set.
+
+ If A&AI mock address is not set it returns 500 HTTP
+ response for resource's method
+
+ Args:
+ method (Callable): method to decorate
+
+ """
+
+ def decorator(self, *args, **kwargs):
+ if not self.AAI_MOCK_URL:
+ return "A&AI mock address not set", 500
+ return method(self, *args, **kwargs)
+
+ return decorator
+
+
+class ServiceInstance(SoResource):
+ """Service instance resource class."""
+
+ def delete(self, service_instance_id: str) -> Dict[str, Dict[str, str]]:
+ """Delete service instance.
+
+ Remove service instance data from SERVICE_INSTANCES
+ dictionary.
+
+ Args:
+ service_instance_id (str): Service instance id key value
+
+ Returns:
+ Dict[str, Dict[str, str]]: Deletion request dictionary
+
+ """
+ service_instance = SERVICE_INSTANCES[service_instance_id]
+ requests.delete(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/business/customers/customer/"
+ f"{service_instance['customerId']}/service-subscriptions/service-subscription/"
+ f"{service_instance['serviceSubscriptionId']}/service-instances/service-instance/"
+ f"{service_instance_id}"
+ )
+ )
+ del SERVICE_INSTANCES[service_instance_id]
+ return {"requestReferences": {"requestId": str(uuid4())}}
+
+
+class ServiceInstanceList(SoResource):
+ """Service instances list resource."""
+
+ @SoResource.check_aai_mock_address
+ def post(self) -> Dict[str, Dict[str, str]]:
+ """Create service instance.
+
+ Create service instance data dictionary.
+ Call request to A&AI mock to create service instance there.
+
+ Returns:
+ Dict[str, Dict[str, str]]: Creation request dictionary
+
+ """
+ instance_id = str(uuid4())
+ request_data = request.get_json()
+ customer_id = request_data["requestDetails"]["subscriberInfo"][
+ "globalSubscriberId"
+ ]
+ service_subscription_id = request_data["requestDetails"]["requestParameters"][
+ "subscriptionServiceType"
+ ]
+ instance_name = request_data["requestDetails"]["requestInfo"]["instanceName"]
+ service_instance = {
+ "requestId": str(uuid4()),
+ "instanceId": instance_id,
+ "customerId": customer_id,
+ "serviceSubscriptionId": service_subscription_id,
+ "instanceName": instance_name,
+ }
+ requests.post(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/business/customers/customer/{customer_id}/"
+ f"service-subscriptions/service-subscription/{service_subscription_id}/"
+ "service-instances"
+ ),
+ json={
+ "service-instance-name": instance_name,
+ "service-instance-id": instance_id,
+ },
+ )
+ SERVICE_INSTANCES[service_instance["instanceId"]] = service_instance
+ return {"requestReferences": service_instance}
+
+
+class VnfInstance(SoResource):
+ """Vnf instance resource."""
+
+ @SoResource.check_aai_mock_address
+ def delete(
+ self, service_instance_id: str, vnf_instance_id: str
+ ) -> Dict[str, Dict[str, str]]:
+ """Delete vnf instance.
+
+ Remove vnf instanca data from SERVICE_INSTANCES dictionary.
+ Call DELETE request to A&AI mock.
+
+ Args:
+ service_instance_id (str): Service instance id key value
+ vnf_instance_id (str): Vnf instance id key value
+
+ Returns:
+ Dict[str, Dict[str, str]]: Deletion request dictionary.
+
+ """
+ related_service = SERVICE_INSTANCES[service_instance_id]
+ requests.delete(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/business/customers/customer/"
+ f"{related_service['customerId']}/service-subscriptions/service-subscription/"
+ f"{related_service['serviceSubscriptionId']}/service-instances/service-instance/"
+ f"{service_instance_id}/relationship-list"
+ )
+ )
+ return {"requestReferences": {"requestId": str(uuid4())}}
+
+
+class VnfInstanceList(SoResource):
+ """Vnf instances list resource."""
+
+ @SoResource.check_aai_mock_address
+ def post(self, service_instance_id: str) -> Dict[str, Dict[str, str]]:
+ """Create vnf instance.
+
+ Create vnf instance data dictionary.
+ Call request to A&AI mock to create vnf instance there.
+
+ Returns:
+ Dict[str, Dict[str, str]]: Creation request dictionary
+
+ """
+ instance_id = str(uuid4())
+ request_data = request.get_json()
+ related_instance_id = request_data["requestDetails"]["relatedInstanceList"][0][
+ "relatedInstance"
+ ]["instanceId"]
+ related_service = SERVICE_INSTANCES[related_instance_id]
+ requests.post(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/business/customers/customer/{related_service['customerId']}/"
+ f"service-subscriptions/service-subscription/{related_service['serviceSubscriptionId']}/"
+ f"service-instances/service-instance/{related_instance_id}/relationship-list"
+ ),
+ json={
+ "related-to": "generic-vnf",
+ "related-link": f"/aai/v16/network/generic-vnfs/generic-vnf/{instance_id}",
+ },
+ )
+ return {
+ "requestReferences": {"requestId": str(uuid4()), "instanceId": instance_id}
+ }
+
+
+class VfModuleInstance(SoResource):
+ """Vf module instance resource class."""
+
+ @SoResource.check_aai_mock_address
+ def delete(
+ self, service_instance_id: str, vnf_instance_id: str, vf_module_instance_id: str
+ ) -> Dict[str, Dict[str, str]]:
+ """Delete vf module instance.
+
+ Call DELETE request to A&AI mock to delete vf module instance.
+
+ Args:
+ service_instance_id (str): Service instance id key value.
+ vnf_instance_id (str): Vnf instance id key value.
+ vf_module_instance_id (str): Vf module instance id key value.
+
+ Returns:
+ Dict[str, Dict[str, str]]: Deletion request dictionary
+
+ """
+ requests.delete(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/network/generic-vnfs/generic-vnf/"
+ f"{vnf_instance_id}/vf-modules/{vf_module_instance_id}"
+ )
+ )
+ return {"requestReferences": {"requestId": str(uuid4())}}
+
+
+class VfModuleInstanceList(SoResource):
+ """Vf module instances list resource."""
+
+ @SoResource.check_aai_mock_address
+ def post(
+ self, service_instance_id: str, vnf_instance_id: str
+ ) -> Dict[str, Dict[str, str]]:
+ """Create vf module instance.
+
+ Call POST request to A&AI mock to create vf module instance.
+
+ Args:
+ service_instance_id (str): Service instance id key value
+ vnf_instance_id (str): Vnf instance id key value
+
+ Returns:
+ Dict[str, Dict[str, str]]: Creation request dictionary
+
+ """
+ instance_id = str(uuid4())
+ requests.post(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/network/generic-vnfs/generic-vnf/"
+ f"{vnf_instance_id}/vf-modules"
+ ),
+ json={"vf-module-id": instance_id},
+ )
+ return {
+ "requestReferences": {"requestId": str(uuid4()), "instanceId": instance_id}
+ }
+
+
+class NetworkInstance(SoResource):
+ """Network instance resource."""
+
+ @SoResource.check_aai_mock_address
+ def delete(
+ self, service_instance_id: str, network_instance_id: str
+ ) -> Dict[str, Dict[str, str]]:
+ """Delete network instance.
+
+ Remove network instanca data from SERVICE_INSTANCES dictionary.
+ Call DELETE request to A&AI mock.
+
+ Args:
+ service_instance_id (str): Service instance id key value
+ network_instance_id (str): Network instance id key value
+
+ Returns:
+ Dict[str, Dict[str, str]]: Deletion request dictionary.
+
+ """
+ related_service = SERVICE_INSTANCES[service_instance_id]
+ requests.delete(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/business/customers/customer/"
+ f"{related_service['customerId']}/service-subscriptions/service-subscription/"
+ f"{related_service['serviceSubscriptionId']}/service-instances/service-instance/"
+ f"{service_instance_id}/relationship-list"
+ )
+ )
+ return {"requestReferences": {"requestId": str(uuid4())}}
+
+
+class NetworkInstanceList(SoResource):
+ """Network instances list resource."""
+
+ @SoResource.check_aai_mock_address
+ def post(self, service_instance_id: str) -> Dict[str, Dict[str, str]]:
+ """Create network instance.
+
+ Create network instance data dictionary.
+ Call request to A&AI mock to create network instance there.
+
+ Returns:
+ Dict[str, Dict[str, str]]: Creation request dictionary
+
+ """
+ instance_id = str(uuid4())
+ request_data = request.get_json()
+ related_instance_id = request_data["requestDetails"]["relatedInstanceList"][0][
+ "relatedInstance"
+ ]["instanceId"]
+ related_service = SERVICE_INSTANCES[related_instance_id]
+ requests.post(
+ (
+ f"{self.AAI_MOCK_URL}/aai/v16/business/customers/customer/{related_service['customerId']}/"
+ f"service-subscriptions/service-subscription/{related_service['serviceSubscriptionId']}/"
+ f"service-instances/service-instance/{related_instance_id}/relationship-list"
+ ),
+ json={
+ "related-to": "l3-network",
+ "related-link": f"/aai/v16/network/l3-networks/l3-network/{instance_id}",
+ },
+ )
+ return {
+ "requestReferences": {"requestId": str(uuid4()), "instanceId": instance_id}
+ }