From ba7629d1f122e64513203c3fad9139bb6e468712 Mon Sep 17 00:00:00 2001 From: Huang Cheng Date: Tue, 3 Mar 2020 09:01:58 +0000 Subject: Add the provisioning management service provider for 5G NRM CM Issue-ID: INT-1387 Signed-off-by: Huang Cheng Change-Id: I23bda3ec2a31569d4857b2f16b9a607c64abd9f0 --- test/mocks/prov-mns-provider/Dockerfile | 13 + test/mocks/prov-mns-provider/README.txt | 60 +++++ test/mocks/prov-mns-provider/docker-compose.yaml | 9 + test/mocks/prov-mns-provider/src/ConfigInfo.json | 5 + .../prov-mns-provider/src/DefinedNRMFunction.json | 11 + .../mocks/prov-mns-provider/src/ProvMnSProvider.py | 270 +++++++++++++++++++++ test/mocks/prov-mns-provider/src/UserInfo.json | 4 + test/mocks/prov-mns-provider/src/preSetMOI.json | 18 ++ test/mocks/prov-mns-provider/src/requirements.txt | 2 + 9 files changed, 392 insertions(+) create mode 100644 test/mocks/prov-mns-provider/Dockerfile create mode 100644 test/mocks/prov-mns-provider/README.txt create mode 100644 test/mocks/prov-mns-provider/docker-compose.yaml create mode 100644 test/mocks/prov-mns-provider/src/ConfigInfo.json create mode 100644 test/mocks/prov-mns-provider/src/DefinedNRMFunction.json create mode 100644 test/mocks/prov-mns-provider/src/ProvMnSProvider.py create mode 100644 test/mocks/prov-mns-provider/src/UserInfo.json create mode 100644 test/mocks/prov-mns-provider/src/preSetMOI.json create mode 100644 test/mocks/prov-mns-provider/src/requirements.txt (limited to 'test/mocks/prov-mns-provider') diff --git a/test/mocks/prov-mns-provider/Dockerfile b/test/mocks/prov-mns-provider/Dockerfile new file mode 100644 index 000000000..748ad4825 --- /dev/null +++ b/test/mocks/prov-mns-provider/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.6 + +WORKDIR /app + +COPY src/requirements.txt ./ + +RUN pip install -r requirements.txt + +COPY src /app + +EXPOSE 8000 + +CMD ["python", "ProvMnSProvider.py"] diff --git a/test/mocks/prov-mns-provider/README.txt b/test/mocks/prov-mns-provider/README.txt new file mode 100644 index 000000000..130d3b383 --- /dev/null +++ b/test/mocks/prov-mns-provider/README.txt @@ -0,0 +1,60 @@ +Python Dependence: python 3.6.x + + +1. To specify the supported NRM function in DefinedNRMFunction.json + + +2. To specify the HTTP server configuration info in ConfigInfo.json + + +3. To specify the User info in UserInfo.json + + +4. To specify the pre-set-MOI info in preSetMOI.json + + +5. To run the HTTP EMS simulator: python ProvMnSProvider.py + +Build the image by using the command: docker build . -t prov-mns-provider +Create the container and start the service by using the command: docker-compose up -d + +The default port number of ProvMnSProvider is : 8000 + +The default username&password of ProvMnSProvider is : root&root + +ProvMnSProvider provdies four RESTful APIs: + +1. Sample PUT request to Create MOI + PUT /ProvisioningMnS/v1500/GNBCUCPFunction/35c369d0-2681-4225-9755-daf98fd20805 + { + "data": { + "attributes": { + "pLMNId": { + "mnc": "01", + "mcc": "001" + }, + "gNBId": "1", + "gNBIdLength": "5", + "gNBCUName": "gnb-01" + }, + "href": "/GNBCUCPFunction/35c369d0-2681-4225-9755-daf98fd20805", + "class": "GNBCUCPFunction", + "id": "35c369d0-2681-4225-9755-daf98fd20805" + } + } + +2. Sample GET request to get MOI attributes + GET /ProvisioningMnS/v1500/GNBCUCPFunction/35c369d0-2681-4225-9755-daf98fd20805?scope=BASE_ONLY&filter=GNBCUCPFunction&fields=gNBId&fields=gNBIdLength + +3. Sample PATCH request to modify MOI attributes + PATCH /ProvisioningMnS/v1500/GNBCUCPFunction/35c369d0-2681-4225-9755-daf98fd20805?scope=BASE_ONLY&filter=GNBCUCPFunction + { + "data": { + "pLMNId": "xxx", + "gNBId": "1234", + "gNBIdLength": "4" + } + } + +4. Sample DELETE request to delete MOI + DELETE /ProvisioningMnS/v1500/GNBCUCPFunction/35c369d0-2681-4225-9755-daf98fd20805?scope=BASE_ONLY&filter=GNBCUCPFunction diff --git a/test/mocks/prov-mns-provider/docker-compose.yaml b/test/mocks/prov-mns-provider/docker-compose.yaml new file mode 100644 index 000000000..c44f21b42 --- /dev/null +++ b/test/mocks/prov-mns-provider/docker-compose.yaml @@ -0,0 +1,9 @@ +version: '3.3' + +services: + ProvMnSProvider: + image: prov-mns-provider:latest + container_name: ProvMnSProvider + ports: + - "8000:8000" + restart: always diff --git a/test/mocks/prov-mns-provider/src/ConfigInfo.json b/test/mocks/prov-mns-provider/src/ConfigInfo.json new file mode 100644 index 000000000..e64a73142 --- /dev/null +++ b/test/mocks/prov-mns-provider/src/ConfigInfo.json @@ -0,0 +1,5 @@ +{ + "ipAddress": "0.0.0.0", + "portNumber": 8000, + "prefix": "/ProvisioningMnS/v1500" +} diff --git a/test/mocks/prov-mns-provider/src/DefinedNRMFunction.json b/test/mocks/prov-mns-provider/src/DefinedNRMFunction.json new file mode 100644 index 000000000..8c685a4a0 --- /dev/null +++ b/test/mocks/prov-mns-provider/src/DefinedNRMFunction.json @@ -0,0 +1,11 @@ +{ + "NRMFunction": [ + "GNBDUFunction", + "GNBCUCPFunction", + "GNBCUUPFunction", + "EP_XnU", + "EP_NgC", + "EP_NgU", + "EP_XnC" + ] +} diff --git a/test/mocks/prov-mns-provider/src/ProvMnSProvider.py b/test/mocks/prov-mns-provider/src/ProvMnSProvider.py new file mode 100644 index 000000000..e9d488ede --- /dev/null +++ b/test/mocks/prov-mns-provider/src/ProvMnSProvider.py @@ -0,0 +1,270 @@ +from http.server import HTTPServer, BaseHTTPRequestHandler +import re +import json +import base64 +from urllib.parse import urlparse, parse_qs + +with open("DefinedNRMFunction.json",'r') as f: + jsonFile = json.loads(f.read()) +SupportingFunctionList = jsonFile["NRMFunction"] + +with open("UserInfo.json",'r') as f: + UserFile = json.loads(f.read()) + +with open("ConfigInfo.json",'r') as f: + ConfigFile = json.loads(f.read()) + +with open("preSetMOI.json",'r') as f: + Cretaed_MOIs = json.loads(f.read()) +Cretaed_MOIs_list = Cretaed_MOIs['preSetMOI'] + +ipAddress = ConfigFile["ipAddress"] +portNumber = ConfigFile["portNumber"] +prefix = ConfigFile["prefix"] + +username = UserFile['userName'] +password = UserFile['password'] +Auth_str = username+":"+password +print(Auth_str) +base64string = base64.b64encode(bytes(Auth_str,'utf-8')) +authheader = "Basic %s" % base64string.decode('utf-8') +print(authheader) + +class ServerHTTP(BaseHTTPRequestHandler): + def do_GET(self): + path = self.path + print("\n**************************** NEW GET REQUEST ********************************") + request = urlparse(path) + print("the PATH of the received GET request:" + request.path) + pathlist = request.path.split('/') + if "/" + pathlist[1] + "/"+ pathlist[2] == prefix: + prefix_check = True + else: + prefix_check = False + className = pathlist[3] + idName = pathlist[4] + response = {} + query_params = parse_qs(request.query) + if self.headers['Authorization'] == authheader and prefix_check is True: + if className in SupportingFunctionList: + try: + print("the value of the scope : "+ str(query_params['scope'])) + print("the value of the filter : "+ str(query_params['filter'])) + print("the value of the fields : "+ str(query_params['fields'])) + except: + print("the request body doesn't follow the standard format") + response['error'] = "the request body doesn't follow the standard format" + print("Fail to get MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + find_moi = False + for MOI in Cretaed_MOIs_list: + if (idName == MOI['id'] and className == MOI['class']): + find_moi = True + try: + attributes = {} + for field in query_params['fields']: + attributes[field] = MOI['attributes'][field] + except: + print("the createed MOI doesn't contain the required attribute") + response['error'] = "the createed MOI doesn't contain the required attribute" + print("Fail to get MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + print("Successfully get MOI object: "+ className+'_'+idName) + response = {"data":[{"href":"/"+className+"/"+idName,"class":className,"id":idName,"attributes":attributes}]} + self.send_response(200) + if (find_moi is False): + response['error'] = {"errorInfo":"MOI does not exist"} + print("Fail to get MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + response['error'] = {"errorInfo":"MOI class not support"} + print("Fail to get MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + self.send_response(401) + if prefix_check is True: + response['error'] = {"errorInfo":"not Authorized"} + else: + response['error'] = {"errorInfo":"wrong prefix"} + self.send_header("Content-type","application/json") + self.end_headers() + buf = json.dumps(response) + self.wfile.write(bytes(buf,'utf-8')) + + def do_PATCH(self): + path = self.path + print("\n**************************** NEW PATCH REQUEST ********************************") + request = urlparse(path) + print("the PATH of the received GET request:" + request.path) + pathlist = request.path.split('/') + if "/" + pathlist[1] + "/"+ pathlist[2] == prefix: + prefix_check = True + else: + prefix_check = False + className = pathlist[3] + idName = pathlist[4] + response = {} + query_params = parse_qs(request.query) + if self.headers['Authorization'] == authheader and prefix_check is True: + if className in SupportingFunctionList: + datas = self.rfile.read(int(self.headers['content-length'])) + json_str = datas.decode('utf-8') + json_str = re.sub('\'','\"', json_str) + json_dict = json.loads(json_str) + try: + print("the value of the scope : "+ str(query_params['scope'])) + print("the value of the filter : "+ str(query_params['filter'])) + print("the modified attribute values : "+json.dumps(json_dict['data'])) + except: + print("the request body doesn't follow the standard format") + response['error'] = "the request body doesn't follow the standard format" + print("Fail to modify MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + find_moi = False + for MOI in Cretaed_MOIs_list: + if (idName == MOI['id'] and className == MOI['class']): + find_moi = True + wrong_attribute = False + for key, value in json_dict['data'].items(): + if (key in MOI['attributes']): + MOI['attributes'][key] = value + else: + wrong_attribute = True + if (wrong_attribute is True): + print("the createed MOI doesn't contain the required attribute") + response['error'] = "the createed MOI doesn't contain the required attribute" + print("Fail to get modify object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + print("Successfully modify MOI object: "+ className+'_'+idName) + response = {"data":[MOI]} + self.send_response(200) + if (find_moi is False): + response['error'] = {"errorInfo":"MOI does not exist"} + print("Fail to get MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + response['error'] = {"errorInfo":"MOI class not support"} + print("Fail to modify MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + self.send_response(401) + if prefix_check is True: + response['error'] = {"errorInfo":"not Authorized"} + else: + response['error'] = {"errorInfo":"wrong prefix"} + self.send_header("Content-type","application/json") + self.end_headers() + buf = json.dumps(response) + self.wfile.write(bytes(buf,'utf-8')) + + def do_DELETE(self): + path = self.path + print("\n**************************** NEW DELETE REQUEST ********************************") + request = urlparse(path) + print("the PATH of the received DELETE request:" + request.path) + pathlist = request.path.split('/') + if "/" + pathlist[1] + "/"+ pathlist[2] == prefix: + prefix_check = True + else: + prefix_check = False + className = pathlist[3] + idName = pathlist[4] + response = {} + query_params = parse_qs(request.query) + if self.headers['Authorization'] == authheader and prefix_check is True: + if className in SupportingFunctionList: + try: + print("the value of the scope : "+ str(query_params['scope'])) + print("the value of the filter : "+ str(query_params['filter'])) + except: + print("the request body doesn't follow the standard format") + response['error'] = "the request body doesn't follow the standard format" + print("Fail to delete MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + find_moi = False + for MOI in Cretaed_MOIs_list: + if (idName == MOI['id'] and className == MOI['class']): + find_moi = True + Cretaed_MOIs_list.remove(MOI) + print("Successfully delete MOI object: "+ className+'_'+idName) + response = {"data":["/"+className+"/"+idName]} + self.send_response(200) + if (find_moi is False): + response['error'] = {"errorInfo":"MOI does not exist"} + print("Fail to delete MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + response['error'] = {"errorInfo":"MOI class not support"} + print("Fail to delete MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + self.send_response(401) + if prefix_check is True: + response['error'] = {"errorInfo":"not Authorized"} + else: + response['error'] = {"errorInfo":"wrong prefix"} + self.send_header("Content-type","application/json") + self.end_headers() + buf = json.dumps(response) + self.wfile.write(bytes(buf,'utf-8')) + + def do_PUT(self): + path = self.path + print("\n**************************** NEW PUT REQUEST ********************************") + print("the PATH of the received PUT request:" + path) + pathlist = path.split('/') + if "/" + pathlist[1] + "/"+ pathlist[2] == prefix: + prefix_check = True + else: + prefix_check = False + className = pathlist[3] + idName = pathlist[4] + response = {} + if self.headers['Authorization'] == authheader and prefix_check is True: + if className in SupportingFunctionList: + datas = self.rfile.read(int(self.headers['content-length'])) + json_str = datas.decode('utf-8') + json_str = re.sub('\'','\"', json_str) + json_dict = json.loads(json_str) + try: + print("the class of the New MOI : "+json_dict['data']['class']) + print("the ID of the New MOI : "+json_dict['data']['id']) + print("the href of the New MOI : "+json_dict['data']['href']) + print("the attributes of the New MOI : "+json.dumps(json_dict['data']['attributes'])) + except: + print("the request body doesn't follow the standard format") + response['error'] = "the request body doesn't follow the standard format" + print("Fail to create MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + print("Successfully create MOI object: "+ className+'/'+idName) + Cretaed_MOIs_list.append(json_dict['data']) + response = json_dict + self.send_response(201) + self.send_header("Location",path) + else: + response['error'] = {"errorInfo":"MOI class not support"} + print("Fail to create MOI object: "+'/' +className+'/'+idName) + self.send_response(406) + else: + self.send_response(401) + if prefix_check is True: + response['error'] = {"errorInfo":"not Authorized"} + else: + response['error'] = {"errorInfo":"wrong prefix"} + self.send_header("Content-type","application/json") + self.end_headers() + buf = json.dumps(response) + self.wfile.write(bytes(buf,'utf-8')) + +def start_server(port): + http_server = HTTPServer((ipAddress, int(port)), ServerHTTP) + http_server.serve_forever() + +if __name__ == "__main__": + start_server(int(portNumber)) diff --git a/test/mocks/prov-mns-provider/src/UserInfo.json b/test/mocks/prov-mns-provider/src/UserInfo.json new file mode 100644 index 000000000..f7f2ba2d8 --- /dev/null +++ b/test/mocks/prov-mns-provider/src/UserInfo.json @@ -0,0 +1,4 @@ +{ + "userName": "root", + "password": "root" +} diff --git a/test/mocks/prov-mns-provider/src/preSetMOI.json b/test/mocks/prov-mns-provider/src/preSetMOI.json new file mode 100644 index 000000000..7d78dbd3d --- /dev/null +++ b/test/mocks/prov-mns-provider/src/preSetMOI.json @@ -0,0 +1,18 @@ +{ + "preSetMOI": [ + { + "attributes": { + "gNBCUName": "gnb-01", + "gNBId": "1", + "gNBIdLength": "5", + "pLMNId": { + "mcc": "001", + "mnc": "01" + } + }, + "class": "GNBCUCPFunction", + "href": "/GNBCUCPFunction/e65d3f05-9558-4e58-aeb0-3a1eae1db742", + "id": "e65d3f05-9558-4e58-aeb0-3a1eae1db742" + } + ] +} diff --git a/test/mocks/prov-mns-provider/src/requirements.txt b/test/mocks/prov-mns-provider/src/requirements.txt new file mode 100644 index 000000000..f622334ac --- /dev/null +++ b/test/mocks/prov-mns-provider/src/requirements.txt @@ -0,0 +1,2 @@ +pip==20.0.2 +wheel==0.29.0 -- cgit 1.2.3-korg