--- /dev/null
+""" Copyright (c) 2019 AT&T Intellectual Property. #\r
+# #\r
+# Licensed under the Apache License, Version 2.0 (the "License"); #\r
+# you may not use this file except in compliance with the License. #\r
+# You may obtain a copy of the License at #\r
+# #\r
+# http://www.apache.org/licenses/LICENSE-2.0 #\r
+# #\r
+# Unless required by applicable law or agreed to in writing, software #\r
+# distributed under the License is distributed on an "AS IS" BASIS, #\r
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #\r
+# See the License for the specific language governing permissions and #\r
+# limitations under the License. #\r
+#############################################################################"""\r
+\r
+\r
+import shutil\r
+import uuid\r
+import zipfile\r
+\r
+import gridfs\r
+from bson import ObjectId\r
+from flask import request, make_response, jsonify, current_app\r
+from gridfs import NoFile\r
+from robot import run\r
+\r
+from . import routes\r
+from .. import database\r
+from ..utils import *\r
+\r
+db_instance = database.DatabaseConfiguration()\r
+\r
+\r
+def verify_directories():\r
+ # retrieve the app object to retrieve the config we created\r
+ app = current_app._get_current_object()\r
+\r
+ if not os.path.isdir(app.config['g_base_folder']):\r
+ os.makedirs(app.config['g_base_folder'])\r
+ if not os.path.isdir(app.config['g_data_folder']):\r
+ os.makedirs(app.config['g_data_folder'])\r
+ if not os.path.isdir(app.config['g_working_folder']):\r
+ os.makedirs(app.config['g_working_folder'])\r
+\r
+\r
+@routes.route("/v1", methods=['POST'])\r
+def robot():\r
+ app = current_app._get_current_object()\r
+\r
+ response_data = {\r
+ "vthResponse": {\r
+ "testDurationMS": "",\r
+ "dateTimeUTC": str(datetime.datetime.now()),\r
+ "abstractMessage": "",\r
+ "resultData": {}\r
+ }\r
+ }\r
+\r
+ start_time = unix_time_millis(datetime.datetime.now())\r
+\r
+ try:\r
+ if not request.is_json:\r
+ raise ValueError('Invalid JSON object.')\r
+\r
+ # get json data from the request\r
+ request_data = request.get_json()\r
+\r
+ # get values for expected keys\r
+ vth_input = try_get_json_value('vthInput', request_data)\r
+ test_data = try_get_json_value('testData', vth_input)\r
+ robot_file_id = try_get_json_value('robotFileId', test_data)\r
+\r
+ # set up a GridFS to access the database\r
+ db = db_instance.get_database()\r
+ fs = gridfs.GridFS(db)\r
+\r
+ # try to find a file using the supplied robot_file_id\r
+ compressed_file = fs.get(ObjectId(robot_file_id))\r
+\r
+ # create the directories used during robot processing if they don't exist\r
+ verify_directories()\r
+\r
+ # generate a folder named by a uuid to organize data for each request\r
+ random_uuid = uuid.uuid4().get_hex()\r
+ data_dir = os.path.join(app.config['g_data_folder'], random_uuid)\r
+ os.mkdir(data_dir)\r
+\r
+ #\r
+ with open(os.path.join(data_dir, compressed_file.name), 'wb') as f:\r
+ f.write(compressed_file.read().__str__())\r
+ f.close()\r
+\r
+ with zipfile.ZipFile(os.path.join(data_dir, compressed_file.name)) as zip_ref:\r
+ # Create a temporary folder for storing extracted test file(s)\r
+ test_dir = os.path.join(app.config['g_working_folder'], random_uuid)\r
+ os.mkdir(test_dir)\r
+\r
+ # Create a separate folder for the output files, so they can be compressed and sent back to the TCU\r
+ test_output_dir = os.path.join(test_dir, 'output')\r
+ os.mkdir(test_output_dir)\r
+\r
+ # Extract the robot tests into the temporary directory\r
+ zip_ref.extractall(test_dir)\r
+\r
+ # Run the robot tests with the outputdir pointed to the temporary directory\r
+ return_code = run(os.path.join(test_dir), outputdir=os.path.join(test_dir, 'output'))\r
+\r
+ # this path is hardcoded so the entire system path isn't included in the zip\r
+ path = './files/results/{uuid}/output'.format(uuid=random_uuid)\r
+ zip_file = zipfile.ZipFile(path + '.zip', 'w', zipfile.ZIP_DEFLATED, allowZip64=True)\r
+ zip_dir(path, zip_file)\r
+ zip_file.close()\r
+\r
+ # save the results to the database\r
+ zf = open(path + '.zip', 'rb')\r
+ result_id = fs.put(zf, filename='output.zip', contentType='application/zip')\r
+ zf.close()\r
+\r
+ response_data['vthResponse']['resultData']['robotStatusCode'] = return_code\r
+ response_data['vthResponse']['resultData']['robotResultFileId'] = str(result_id)\r
+ response_data['vthResponse']['abstractMessage'] = resolve_robot_status_code(return_code)\r
+\r
+\r
+\r
+ # delete data from the local disk\r
+ shutil.rmtree(path.replace('/output', ''))\r
+ shutil.rmtree(data_dir)\r
+\r
+ # record the end time of the test\r
+ end_time = unix_time_millis(datetime.datetime.now())\r
+\r
+ # Calculate the total duration of the test\r
+ total_time = end_time - start_time\r
+\r
+ # Set the test duration in the result\r
+ response_data['vthResponse']['testDurationMS'] = total_time\r
+\r
+ return jsonify(response_data)\r
+ except NoFile as e:\r
+ # this exception can only occur if robot_file_id is set to something, so don't worry about reference precedence.\r
+ end_time = unix_time_millis(datetime.datetime.now())\r
+ total_time = end_time - start_time\r
+\r
+ response_data['vthResponse']['testDurationMS'] = ''\r
+ response_data['vthResponse']['abstractMessage'] = \\r
+ 'An exception occurred after running for {totalTime} milliseconds. ' \\r
+ 'A file with _id {id} was not found in the collection.'.format(id=robot_file_id, totalTime=total_time)\r
+\r
+ response = make_response(json.dumps(response_data))\r
+ return response\r
+\r
+ except Exception as e:\r
+ app.logger.error(e)\r
+ end_time = unix_time_millis(datetime.datetime.now())\r
+ total_time = end_time - start_time\r
+\r
+ response_data['vthResponse']['testDurationMS'] = ''\r
+ response_data['vthResponse']['abstractMessage'] = \\r
+ 'An exception occurred after running for {totalTime} milliseconds. ' \\r
+ 'Exception: {exception}.'.format(exception=str(e), totalTime=total_time)\r
+\r
+ response = make_response(json.dumps(response_data))\r
+\r
+ return response\r