From dceaf3959f4f398452cb0fcfb03372e9bc528ceb Mon Sep 17 00:00:00 2001 From: ecaiyanlinux Date: Mon, 18 May 2020 14:40:53 +0200 Subject: [PATCH] Fix two bugs in simulator & code cleaning Bug 1: a1-interface is now runing single threaded, so need to setup a standalone callback server to test purpose Bug 2: need to pass real ip from nginx to upstream main.py Issue-ID: NONRTRIC-218 Signed-off-by: ecaiyanlinux Change-Id: Ia04cbf6a402aff444f17ddd8e9bd41a19a687791 --- near-rt-ric-simulator/README.md | 10 +++-- near-rt-ric-simulator/nginx.conf | 6 ++- near-rt-ric-simulator/src/OSC_2.1.0/a1.py | 9 ++++- near-rt-ric-simulator/src/OSC_2.1.0/main.py | 25 ++++--------- near-rt-ric-simulator/src/STD_1.1.3/callBack.py | 43 ++++++++++++++++++++++ near-rt-ric-simulator/src/common/maincommon.py | 26 ++----------- near-rt-ric-simulator/src/start.sh | 4 ++ near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh | 6 +-- near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh | 2 +- 9 files changed, 82 insertions(+), 49 deletions(-) create mode 100644 near-rt-ric-simulator/src/STD_1.1.3/callBack.py diff --git a/near-rt-ric-simulator/README.md b/near-rt-ric-simulator/README.md index 8268136..8eb97c0 100644 --- a/near-rt-ric-simulator/README.md +++ b/near-rt-ric-simulator/README.md @@ -145,9 +145,11 @@ An env variable, A1\_VERSION need to be passed to the container at start to sele An env variable, REMOTE_HOSTS_LOGGING, can be set (any value is ok) and the the counter remote\_hosts will log the host names of all remote hosts that has accessed the A1 URIs. If host names cannot be resolved, the ip address of the remote host is logged instead. This logging is default off so must be configured to be enabled. If not configured, the counter remote\_hosts will return a fixed text indicating that host name logging is not enabled. Use this feature with caution, remote host lookup may take time in certain environments. The simulator can also run using the https protocol. The enable https, a valid certificate and key need to provided. There is self-signed certificate available in the certificate dir and that dir shall be mounted to the container to make it available -In docker run the full command could look like this:
'docker run -it -p 8085:8085 -e A1\_VERSION=STD\_1.1.3 a1test' where the variable for A1 version is set with the '-e' flag.
-With logging of remote host enabled:
'docker run -it -p 8085:8085 -e A1\_VERSION=STD\_1.1.3 -e REMOTE_HOSTS_LOGGING=1 a1test'
-Example of running https with secure port and certificate dir mounted
'docker run -it -p 8085:8085 -e A1\_VERSION=STD\_1.1.3 -e REMOTE_HOSTS_LOGGING=1 --read-only --volume /PATH_TO_CERT_DIR/certificate:/usr/src/app/cert a1test' +In docker run the full command could look like this:
'docker run -it -p 8085:8085 -p 8185:8185 -e A1\_VERSION=STD\_1.1.3 -e REMOTE_HOSTS_LOGGING=1 --volume /PATH_TO_CERT_DIR/certificate:/usr/src/app/cert a1test' +http port 8085 and https port 8185 +The variable for A1 version is set with the '-e' flag. +With logging of remote host enabled "-e REMOTE_HOSTS_LOGGING=1 " +With certificate dir mounted "--volume /PATH_TO_CERT_DIR/certificate:/usr/src/app/cert" # Updating the openapi specs The openapi specifications are stored in the 'api/<version>/'. If adding/replacing with a new file, make sure to copy the 'operationId' parameter for each operation to the new file. @@ -163,7 +165,7 @@ Go to the test folder of the selected version, 'test/<version>/. Note that test can be performed both using the nonsecure http port and the secure https port. -Build and start the simulator container using: ./build\_and\_start.sh nonsecure|secure +Build and start the simulator container using: ./build\_and\_start.sh This will build and start the container in interactive mode. The built container only resides in the local docker repository. Note, the default port is 8085 for http and 8185 for https. When running the simulator as a container, the defualt ports can be re-mapped to any port on the localhost. diff --git a/near-rt-ric-simulator/nginx.conf b/near-rt-ric-simulator/nginx.conf index 5ba9dbe..f21e173 100644 --- a/near-rt-ric-simulator/nginx.conf +++ b/near-rt-ric-simulator/nginx.conf @@ -37,9 +37,13 @@ http { ssl_certificate_key /usr/src/app/cert/key.crt; ssl_password_file /usr/src/app/cert/pass; + # serve dynamic requests location / { - proxy_pass http://localhost:2222; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://localhost:2222; } } ## diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/a1.py b/near-rt-ric-simulator/src/OSC_2.1.0/a1.py index eb4209c..59c47ef 100644 --- a/near-rt-ric-simulator/src/OSC_2.1.0/a1.py +++ b/near-rt-ric-simulator/src/OSC_2.1.0/a1.py @@ -46,7 +46,9 @@ def get_all_policy_types(): if ((r := check_modified_response()) is not None): return r - return (list(policy_instances.keys()), 200) + res = list(policy_instances.keys()) + res = list(map(int, res)) + return (res, 200) # API Function: Get a policy type def get_policy_type(policy_type_id): @@ -93,6 +95,11 @@ def create_policy_type(policy_type_id): if ((r := check_modified_response()) is not None): return r + try: + val=int(policy_type_id) + except: + return Response("The policy type id is not an int", 400, mimetype='text/plain') + policy_type_id=str(policy_type_id) if (policy_type_id in policy_instances.keys()): diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/main.py b/near-rt-ric-simulator/src/OSC_2.1.0/main.py index dc25626..1bc6128 100644 --- a/near-rt-ric-simulator/src/OSC_2.1.0/main.py +++ b/near-rt-ric-simulator/src/OSC_2.1.0/main.py @@ -22,7 +22,7 @@ import os import requests from pathlib import Path -from flask import Flask, escape, request, Response +from flask import Flask, escape, request, Response, jsonify from jsonschema import validate from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, forced_settings, hosts_set from maincommon import * @@ -32,22 +32,6 @@ from time import sleep check_apipath() app = connexion.FlaskApp(__name__, specification_dir=apipath) -t=[] ##varialbe for test purpose - -#long poll -@app.route('/long', methods=['GET']) -def longpoll(): - global t - sleep(10) - t.append(1) - return Response(str(t), 200, mimetype='text/plain') - -#short poll -@app.route('/short', methods=['GET']) -def shortpoll(): - global t - t.append(2) - return Response(str(t), 200, mimetype='text/plain') #Check alive function @app.route('/', methods=['GET']) @@ -55,6 +39,13 @@ def test(): return Response("OK", 200, mimetype='text/plain') +@app.route('/ip', methods=['GET']) +def get_ip(): + if request.environ.get('HTTP_X_FORWARDED_FOR') is None: + return jsonify({'ip': request.environ['REMOTE_ADDR']}), 200 + else: + return jsonify({'ip': request.environ['HTTP_X_FORWARDED_FOR']}), 200 + #Return the current and all supported yamls for the this container @app.route('/container_interfaces', methods=['GET']) def container_interfaces(): diff --git a/near-rt-ric-simulator/src/STD_1.1.3/callBack.py b/near-rt-ric-simulator/src/STD_1.1.3/callBack.py new file mode 100644 index 0000000..728c8da --- /dev/null +++ b/near-rt-ric-simulator/src/STD_1.1.3/callBack.py @@ -0,0 +1,43 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. 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 + +app = Flask(__name__) + +#Check alive function +@app.route('/', methods=['GET']) +def test(): + + return Response("OK", 200, mimetype='text/plain') + +#Receive status (only for testing callbacks) +#/statustest +@app.route('/statustest', methods=['POST', 'PUT']) +def statustest(): + try: + data = request.data + data = json.loads(data) + except: + return Response("The status data is corrupt or missing.", 400, mimetype='text/plain') + + return Response(json.dumps(data), 200, mimetype='application/json') + +port_number = 2223 + +app.run(port=port_number, host="127.0.0.1", threaded=False) \ No newline at end of file diff --git a/near-rt-ric-simulator/src/common/maincommon.py b/near-rt-ric-simulator/src/common/maincommon.py index ee52d55..94a0b6d 100644 --- a/near-rt-ric-simulator/src/common/maincommon.py +++ b/near-rt-ric-simulator/src/common/maincommon.py @@ -46,7 +46,10 @@ def get_supported_interfaces_response(): # Remote host lookup and store host name in a set def extract_host_name(hosts_set, request): if (remote_hosts_logging is not None): - host_ip=str(request.environ['REMOTE_ADDR']) + if request.environ.get('HTTP_X_FORWARDED_FOR') is None: + host_ip=str(request.environ['REMOTE_ADDR']) + else: + host_ip=str(request.environ['HTTP_X_FORWARDED_FOR']) prefix='::ffff:' if (host_ip.startswith('::ffff:')): host_ip=host_ip[len(prefix):] @@ -57,24 +60,3 @@ def extract_host_name(hosts_set, request): hosts_set.add(host_ip) else: hosts_set.add("logging_of_remote_host_names_not_enabled") - -# Check if cert is available and return a sec context, if not return 'None' -def get_security_context(): - - try: - path="/usr/src/app/cert" - if (os.path.isdir(path)): - certpath=path+"/cert.crt" - keypath=path+"/key.crt" - if (os.path.isfile(certpath) and os.path.isfile(keypath)): - context = ssl.SSLContext(ssl.PROTOCOL_TLS) - context.load_cert_chain(certpath, keypath, password="test") - return context - else: - print("Cert and/or key does not exists in dir "+str(path)) - - else: - print("Path "+str(path)+" to certificate and key does not exists") - except Exception as e: - print("Problem when loading cert and key: "+str(e)) - return None diff --git a/near-rt-ric-simulator/src/start.sh b/near-rt-ric-simulator/src/start.sh index 73491bd..9d5acd8 100755 --- a/near-rt-ric-simulator/src/start.sh +++ b/near-rt-ric-simulator/src/start.sh @@ -40,6 +40,10 @@ cd $1 #start nginx nginx -c /usr/src/app/nginx.conf +#start callBack server +echo "Path to callBack.py: "$PWD +python -u callBack.py & + #start near-rt-ric-simulator echo "Path to main.py: "$PWD python -u main.py diff --git a/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh b/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh index f77e347..9fd2352 100755 --- a/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh +++ b/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh @@ -95,7 +95,7 @@ RESULT="" do_curl PUT /a1-p/policytypes/1 201 jsonfiles/pt1.json echo "=== API: Get policy type ids, shall contain type 1 ==" -RESULT="json:[ \"1\" ]" +RESULT="json:[ 1 ]" do_curl GET /a1-p/policytypes 200 echo "=== API: Get instances for type 1, shall be empty ===" @@ -143,7 +143,7 @@ RESULT="Policy type 2 is OK." do_curl PUT '/policytype?id=2' 200 jsonfiles/pt1.json echo "=== API: Get policy type ids, shall contain type 1 and 2 ==" -RESULT="json:[ \"1\", \"2\" ]" +RESULT="json:[ 1, 2 ]" do_curl GET /a1-p/policytypes 200 echo "=== Get policy type ids, shall contain type 1 and 2 ==" @@ -159,7 +159,7 @@ RESULT="" do_curl DELETE '/policytype?id=2' 204 jsonfiles/pt1.json echo "=== API: Get policy type ids, shall contain type 1 ==" -RESULT="json:[ \"1\" ]" +RESULT="json:[ 1 ]" do_curl GET /a1-p/policytypes 200 echo "=== Load a policy type: 2 ===" diff --git a/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh b/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh index 2b34cf3..bcf25da 100755 --- a/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh +++ b/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh @@ -97,7 +97,7 @@ do_curl PUT /A1-P/v1/policies/pi2 201 jsonfiles/pi2.json echo "=== API: Update policy instance pi2 ===" RESULT="json:{\"scope\": {\"ueId\": \"ue2\", \"groupId\": \"group2\", \"sliceId\": \"slice2\", \"qosId\": \"qos2\", \"cellId\": \"cell2\"}, \"statement\": {\"priorityLevel\": 10}}" -do_curl PUT '/A1-P/v1/policies/pi2?notificationDestination='$HTTPX'://localhost:'$PORT'/statustest' 200 jsonfiles/pi2.json +do_curl PUT '/A1-P/v1/policies/pi2?notificationDestination=http://localhost:2223/statustest' 200 jsonfiles/pi2.json echo "=== API: Get policy instances, shall contain pi1 and pi2==" RESULT="json:[ \"pi1\", \"pi2\" ]" -- 2.16.6