aboutsummaryrefslogtreecommitdiffstats
path: root/test/mocks/ran-nssmf-simulator/RanNssmfSimulator
diff options
context:
space:
mode:
authorEnbo Wang <wangenbo@huawei.com>2020-09-18 11:06:12 +0800
committerEnbo Wang <wangenbo@huawei.com>2020-09-19 17:25:04 +0800
commitb764f221db38dd0d0fb3bad908e5d1329721730d (patch)
tree0a60d0bc8a3f9b6ac0a941a955ba0007fe57cd06 /test/mocks/ran-nssmf-simulator/RanNssmfSimulator
parentedbe50b80ce489b5ef9f30c9cd72f2dbcf2032d9 (diff)
Add an External RAN NSSMF simulator
Change-Id: I770091159dd1f953d8a567ccd2bd7f6d21f27649 Issue-ID: INT-1707 Signed-off-by: Enbo Wang <wangenbo@huawei.com>
Diffstat (limited to 'test/mocks/ran-nssmf-simulator/RanNssmfSimulator')
-rw-r--r--test/mocks/ran-nssmf-simulator/RanNssmfSimulator/AuthManager.py127
-rw-r--r--test/mocks/ran-nssmf-simulator/RanNssmfSimulator/MainApp.py107
-rw-r--r--test/mocks/ran-nssmf-simulator/RanNssmfSimulator/NssManager.py48
-rw-r--r--test/mocks/ran-nssmf-simulator/RanNssmfSimulator/SliceDataType.py59
-rw-r--r--test/mocks/ran-nssmf-simulator/RanNssmfSimulator/__init__.py0
-rw-r--r--test/mocks/ran-nssmf-simulator/RanNssmfSimulator/etc/auth.json7
-rw-r--r--test/mocks/ran-nssmf-simulator/RanNssmfSimulator/utils.py44
7 files changed, 392 insertions, 0 deletions
diff --git a/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/AuthManager.py b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/AuthManager.py
new file mode 100644
index 000000000..6a52f516f
--- /dev/null
+++ b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/AuthManager.py
@@ -0,0 +1,127 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+
+"""
+ Used to get and check Access Token by SO NSSMF adapter.
+"""
+
+import json
+import uuid
+import time
+import sched
+import threading
+from schematics.types import StringType
+from schematics.models import Model
+
+from .utils import getLogger, AUTH_DB, TOKEN_EXPIRES_TIME, TOKEN_CLEAN_TIME
+
+
+logger = getLogger("AuthManager")
+lock = threading.Lock()
+
+
+class AuthRequest(Model):
+ grantType = StringType(required=True)
+ userName = StringType(required=True)
+ value = StringType(required=True)
+
+
+class AuthInfo(object):
+ def __init__(self, authRequest, expires):
+ self.authRequest = authRequest
+ self.expiredTime = int(time.time()) + expires * 60
+
+
+class AuthError(ValueError):
+ pass
+
+
+class TokenError(ValueError):
+ pass
+
+
+_AUTH_TOKEN = {}
+
+
+def cleanExpiredToken():
+ s = sched.scheduler(time.time, time.sleep)
+
+ def doCleanExpiredToken():
+ current_time = int(time.time())
+
+ expiredTokens = []
+ for authToken in _AUTH_TOKEN:
+ if current_time > _AUTH_TOKEN[authToken].expiredTime:
+ expiredTokens.append(authToken)
+ logger.debug("Auth token %s is expired and will be deleted" % authToken)
+
+ with lock:
+ for authToken in expiredTokens:
+ del _AUTH_TOKEN[authToken]
+
+ s.enter(TOKEN_CLEAN_TIME, 1, doCleanExpiredToken)
+
+ s.enter(TOKEN_CLEAN_TIME, 1, doCleanExpiredToken)
+
+ s.run()
+
+
+def checkAuth(authRequest):
+ with open(AUTH_DB) as f:
+ authDB = json.load(f)
+
+ if authRequest["grantType"].lower() != "password":
+ raise AuthError("Unsupported grantType %s" % authRequest["grantType"])
+
+ for authItem in authDB:
+ if authItem["userName"].lower() == authRequest["userName"].lower() \
+ and authItem["value"] == authRequest["value"]:
+ break
+ else:
+ raise AuthError("userName or password is error")
+
+
+def generateAuthToken(authRequest):
+ token = uuid.uuid4().hex
+ with lock:
+ _AUTH_TOKEN[token] = AuthInfo(authRequest, TOKEN_EXPIRES_TIME)
+
+ return {
+ "accessToken": token,
+ "expires": TOKEN_EXPIRES_TIME
+ }
+
+
+def checkAuthToken(requestHeaders):
+ authToken = requestHeaders.get("X-Auth-Token")
+ logger.debug("X-Auth-Token: %s" % authToken)
+
+ if not authToken:
+ raise TokenError("Auth token is missing")
+
+ if authToken not in _AUTH_TOKEN:
+ raise TokenError("Auth token is error")
+
+ current_time = int(time.time())
+ if current_time > _AUTH_TOKEN[authToken].expiredTime:
+ raise TokenError("Auth token is expired")
+
+
+def startAuthManagerJob():
+ cleanThread = threading.Thread(target=cleanExpiredToken)
+ cleanThread.daemon = True
+
+ cleanThread.start()
diff --git a/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/MainApp.py b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/MainApp.py
new file mode 100644
index 000000000..6074e7634
--- /dev/null
+++ b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/MainApp.py
@@ -0,0 +1,107 @@
+#! /usr/bin/python3
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+
+import json
+from flask import Flask, request, Response
+from schematics.exceptions import DataError
+
+from .utils import REST_PORT, LOGGING_LEVEL
+from .SliceDataType import AllocateNssi, DeAllocateNssi
+from . import AuthManager
+from . import NssManager
+
+
+app = Flask(__name__)
+app.logger.setLevel(LOGGING_LEVEL)
+
+
+@app.errorhandler(DataError)
+def handleRequestException(e):
+ app.logger.error(e)
+ response = Response()
+ response.status_code = 400
+ return response
+
+
+@app.errorhandler(AuthManager.AuthError)
+def handleAuthException(e):
+ app.logger.error(e)
+ response = Response()
+ response.status_code = 400
+ return response
+
+
+@app.errorhandler(AuthManager.TokenError)
+def handleAuthException(e):
+ app.logger.error(e)
+ response = Response()
+ response.status_code = 401
+ return response
+
+
+@app.errorhandler(NssManager.NssError)
+def handleNssException(e):
+ app.logger.error(e)
+ response = Response()
+ response.status_code = 400
+ return response
+
+
+@app.route("/api/rest/securityManagement/v1/oauth/token", methods=['POST'])
+def handleAuthToken():
+ """
+ Used to get Access Token by SO NSSMF adapter.
+ """
+ app.logger.debug("Receive request:\n%s" % json.dumps(request.json, indent=2))
+
+ AuthManager.AuthRequest(request.json).validate()
+ AuthManager.checkAuth(request.json)
+
+ return AuthManager.generateAuthToken(request.json), 201
+
+
+@app.route("/ObjectManagement/NSS/SliceProfiles", methods=['POST'])
+def handleAllocateNssi():
+ AuthManager.checkAuthToken(request.headers)
+
+ app.logger.info("Receive AllocateNssi request:\n%s" % json.dumps(request.json, indent=2))
+
+ AllocateNssi(request.json).validate()
+
+ return NssManager.allocateNssi(request.json), 200
+
+
+@app.route("/ObjectManagement/NSS/SliceProfiles/<string:sliceProfileId>", methods=['DELETE'])
+def handleDeallocateNssi(sliceProfileId):
+ AuthManager.checkAuthToken(request.headers)
+
+ app.logger.info("Receive DeallocateNssi request for sliceProfileId %s:\n%s"
+ % (sliceProfileId, json.dumps(request.json, indent=2)))
+
+ DeAllocateNssi(request.json).validate()
+
+ return NssManager.deallocateNssi(sliceProfileId, request.json), 200
+
+
+def main():
+ AuthManager.startAuthManagerJob()
+ app.run("0.0.0.0", REST_PORT, False, ssl_context="adhoc")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/NssManager.py b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/NssManager.py
new file mode 100644
index 000000000..f515968f1
--- /dev/null
+++ b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/NssManager.py
@@ -0,0 +1,48 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+
+import uuid
+
+from .utils import getLogger
+
+
+logger = getLogger("NssManager")
+
+
+class NssError(ValueError):
+ pass
+
+
+def allocateNssi(requestBody):
+ sliceProfile = requestBody["attributeListIn"]
+ sliceProfileId = sliceProfile["sliceProfileId"]
+
+ nSSId = uuid.uuid4().hex
+
+ responseBody = {
+ "attributeListOut": {},
+ "href": nSSId
+ }
+
+ logger.info("Allocate NSSI for sliceProfileId %s success, nSSId: %s" % (sliceProfileId, nSSId))
+ return responseBody
+
+
+def deallocateNssi(sliceProfileId, requestBody):
+ nSSId = requestBody["nSSId"]
+
+ logger.info("Deallocate NSSI for sliceProfileId %s success, nSSId: %s" % (sliceProfileId, nSSId))
+ return ""
diff --git a/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/SliceDataType.py b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/SliceDataType.py
new file mode 100644
index 000000000..10ee2c765
--- /dev/null
+++ b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/SliceDataType.py
@@ -0,0 +1,59 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+
+from schematics.types import BaseType, StringType, IntType, LongType
+from schematics.types.compound import ModelType, ListType, DictType
+from schematics.models import Model
+
+
+class PerfReqEmbb(Model):
+ expDataRateDL = IntType()
+ expDataRateUL = IntType()
+ areaTrafficCapDL = IntType()
+ areaTrafficCapUL = IntType()
+ overallUserDensity = IntType()
+ activityFactor = IntType()
+
+
+class PerfReqUrllc(Model):
+ """TODO"""
+ pass
+
+
+class PerfReq(Model):
+ perfReqEmbb = ModelType(PerfReqEmbb)
+ # perfReqUrllc = ModelType(PerfReqUrllc)
+ perfReqUrllc = DictType(BaseType)
+
+
+class SliceProfile(Model):
+ sliceProfileId = StringType(required=True)
+ sNSSAIList = ListType(StringType(required=True))
+ pLMNIdList = ListType(StringType(required=True))
+ perfReq = ModelType(PerfReq, required=True)
+ maxNumberofUEs = LongType()
+ coverageAreaTAList = ListType(IntType())
+ latency = IntType()
+ uEMobilityLevel = StringType()
+ resourceSharingLevel = StringType()
+
+
+class AllocateNssi(Model):
+ attributeListIn = ModelType(SliceProfile)
+
+
+class DeAllocateNssi(Model):
+ nSSId = StringType(required=True)
diff --git a/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/__init__.py b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/__init__.py
diff --git a/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/etc/auth.json b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/etc/auth.json
new file mode 100644
index 000000000..23e9376e0
--- /dev/null
+++ b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/etc/auth.json
@@ -0,0 +1,7 @@
+[
+ {
+ "grantType": "password",
+ "userName": "admin",
+ "value": "123456"
+ }
+]
diff --git a/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/utils.py b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/utils.py
new file mode 100644
index 000000000..f0b99119a
--- /dev/null
+++ b/test/mocks/ran-nssmf-simulator/RanNssmfSimulator/utils.py
@@ -0,0 +1,44 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+
+import os
+import logging
+
+REST_PORT = int(os.getenv("RAN_NSSMF_REST_PORT", "8443"))
+LOGGING_LEVEL = os.getenv("RAN_NSSMF_LOGGING_LEVEL", "INFO")
+
+TOKEN_EXPIRES_TIME = int(os.getenv("RAN_NSSMF_TOKEN_EXPIRES_TIME", "30"))
+TOKEN_CLEAN_TIME = int(os.getenv("RAN_NSSMF_TOKEN_CLEAN_TIME", "180"))
+
+MAIN_DIR = os.path.dirname(os.path.abspath(__file__))
+AUTH_DB_FILE = os.path.join(MAIN_DIR, "etc", "auth.json")
+
+AUTH_DB = os.getenv("RAN_NSSMF_AUTH_DB", AUTH_DB_FILE)
+
+
+LOGGER_FORMAT = "[%(asctime)-15s] %(levelname)s in %(name)s: %(message)s"
+
+
+def getLogger(name, level=LOGGING_LEVEL, fmt=LOGGER_FORMAT):
+ logger = logging.getLogger(name)
+ logger.setLevel(level)
+
+ formatter = logging.Formatter(fmt)
+ cmd_handler = logging.StreamHandler()
+ cmd_handler.setFormatter(formatter)
+ logger.addHandler(cmd_handler)
+
+ return logger