X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=it%2Fotf.git;a=blobdiff_plain;f=otf-robot-test-head%2Fapp%2Froutes%2Frobot_processor.py;fp=otf-robot-test-head%2Fapp%2Froutes%2Frobot_processor.py;h=4444858b5ae1a46440423c0fba5b575ab32a99f2;hp=0000000000000000000000000000000000000000;hb=f49bd1efeaaddd4891c1f329b18d8cfb28b3e75b;hpb=5d8b2580c97e466f9c5a6c78693c24277d94244c diff --git a/otf-robot-test-head/app/routes/robot_processor.py b/otf-robot-test-head/app/routes/robot_processor.py new file mode 100644 index 0000000..4444858 --- /dev/null +++ b/otf-robot-test-head/app/routes/robot_processor.py @@ -0,0 +1,164 @@ +""" Copyright (c) 2019 AT&T Intellectual Property. # +# # +# 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 shutil +import uuid +import zipfile + +import gridfs +from bson import ObjectId +from flask import request, make_response, jsonify, current_app +from gridfs import NoFile +from robot import run + +from . import routes +from .. import database +from ..utils import * + +db_instance = database.DatabaseConfiguration() + + +def verify_directories(): + # retrieve the app object to retrieve the config we created + app = current_app._get_current_object() + + if not os.path.isdir(app.config['g_base_folder']): + os.makedirs(app.config['g_base_folder']) + if not os.path.isdir(app.config['g_data_folder']): + os.makedirs(app.config['g_data_folder']) + if not os.path.isdir(app.config['g_working_folder']): + os.makedirs(app.config['g_working_folder']) + + +@routes.route("/v1", methods=['POST']) +def robot(): + app = current_app._get_current_object() + + response_data = { + "vthResponse": { + "testDurationMS": "", + "dateTimeUTC": str(datetime.datetime.now()), + "abstractMessage": "", + "resultData": {} + } + } + + start_time = unix_time_millis(datetime.datetime.now()) + + try: + if not request.is_json: + raise ValueError('Invalid JSON object.') + + # get json data from the request + request_data = request.get_json() + + # get values for expected keys + vth_input = try_get_json_value('vthInput', request_data) + test_data = try_get_json_value('testData', vth_input) + robot_file_id = try_get_json_value('robotFileId', test_data) + + # set up a GridFS to access the database + db = db_instance.get_database() + fs = gridfs.GridFS(db) + + # try to find a file using the supplied robot_file_id + compressed_file = fs.get(ObjectId(robot_file_id)) + + # create the directories used during robot processing if they don't exist + verify_directories() + + # generate a folder named by a uuid to organize data for each request + random_uuid = uuid.uuid4().get_hex() + data_dir = os.path.join(app.config['g_data_folder'], random_uuid) + os.mkdir(data_dir) + + # + with open(os.path.join(data_dir, compressed_file.name), 'wb') as f: + f.write(compressed_file.read().__str__()) + f.close() + + with zipfile.ZipFile(os.path.join(data_dir, compressed_file.name)) as zip_ref: + # Create a temporary folder for storing extracted test file(s) + test_dir = os.path.join(app.config['g_working_folder'], random_uuid) + os.mkdir(test_dir) + + # Create a separate folder for the output files, so they can be compressed and sent back to the TCU + test_output_dir = os.path.join(test_dir, 'output') + os.mkdir(test_output_dir) + + # Extract the robot tests into the temporary directory + zip_ref.extractall(test_dir) + + # Run the robot tests with the outputdir pointed to the temporary directory + return_code = run(os.path.join(test_dir), outputdir=os.path.join(test_dir, 'output')) + + # this path is hardcoded so the entire system path isn't included in the zip + path = './files/results/{uuid}/output'.format(uuid=random_uuid) + zip_file = zipfile.ZipFile(path + '.zip', 'w', zipfile.ZIP_DEFLATED, allowZip64=True) + zip_dir(path, zip_file) + zip_file.close() + + # save the results to the database + zf = open(path + '.zip', 'rb') + result_id = fs.put(zf, filename='output.zip', contentType='application/zip') + zf.close() + + response_data['vthResponse']['resultData']['robotStatusCode'] = return_code + response_data['vthResponse']['resultData']['robotResultFileId'] = str(result_id) + response_data['vthResponse']['abstractMessage'] = resolve_robot_status_code(return_code) + + + + # delete data from the local disk + shutil.rmtree(path.replace('/output', '')) + shutil.rmtree(data_dir) + + # record the end time of the test + end_time = unix_time_millis(datetime.datetime.now()) + + # Calculate the total duration of the test + total_time = end_time - start_time + + # Set the test duration in the result + response_data['vthResponse']['testDurationMS'] = total_time + + return jsonify(response_data) + except NoFile as e: + # this exception can only occur if robot_file_id is set to something, so don't worry about reference precedence. + end_time = unix_time_millis(datetime.datetime.now()) + total_time = end_time - start_time + + response_data['vthResponse']['testDurationMS'] = '' + response_data['vthResponse']['abstractMessage'] = \ + 'An exception occurred after running for {totalTime} milliseconds. ' \ + 'A file with _id {id} was not found in the collection.'.format(id=robot_file_id, totalTime=total_time) + + response = make_response(json.dumps(response_data)) + return response + + except Exception as e: + app.logger.error(e) + end_time = unix_time_millis(datetime.datetime.now()) + total_time = end_time - start_time + + response_data['vthResponse']['testDurationMS'] = '' + response_data['vthResponse']['abstractMessage'] = \ + 'An exception occurred after running for {totalTime} milliseconds. ' \ + 'Exception: {exception}.'.format(exception=str(e), totalTime=total_time) + + response = make_response(json.dumps(response_data)) + + return response