1 """ Copyright (c) 2019 AT&T Intellectual Property. #
\r
3 # Licensed under the Apache License, Version 2.0 (the "License"); #
\r
4 # you may not use this file except in compliance with the License. #
\r
5 # You may obtain a copy of the License at #
\r
7 # http://www.apache.org/licenses/LICENSE-2.0 #
\r
9 # Unless required by applicable law or agreed to in writing, software #
\r
10 # distributed under the License is distributed on an "AS IS" BASIS, #
\r
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
\r
12 # See the License for the specific language governing permissions and #
\r
13 # limitations under the License. #
\r
14 #############################################################################"""
\r
22 from bson import ObjectId
\r
23 from flask import request, make_response, jsonify, current_app
\r
24 from gridfs import NoFile
\r
25 from robot import run
\r
27 from . import routes
\r
28 from .. import database
\r
29 from ..utils import *
\r
31 db_instance = database.DatabaseConfiguration()
\r
34 def verify_directories():
\r
35 # retrieve the app object to retrieve the config we created
\r
36 app = current_app._get_current_object()
\r
38 if not os.path.isdir(app.config['g_base_folder']):
\r
39 os.makedirs(app.config['g_base_folder'])
\r
40 if not os.path.isdir(app.config['g_data_folder']):
\r
41 os.makedirs(app.config['g_data_folder'])
\r
42 if not os.path.isdir(app.config['g_working_folder']):
\r
43 os.makedirs(app.config['g_working_folder'])
\r
46 @routes.route("/v1", methods=['POST'])
\r
48 app = current_app._get_current_object()
\r
52 "testDurationMS": "",
\r
53 "dateTimeUTC": str(datetime.datetime.now()),
\r
54 "abstractMessage": "",
\r
59 start_time = unix_time_millis(datetime.datetime.now())
\r
62 if not request.is_json:
\r
63 raise ValueError('Invalid JSON object.')
\r
65 # get json data from the request
\r
66 request_data = request.get_json()
\r
68 # get values for expected keys
\r
69 vth_input = try_get_json_value('vthInput', request_data)
\r
70 test_data = try_get_json_value('testData', vth_input)
\r
71 robot_file_id = try_get_json_value('robotFileId', test_data)
\r
73 # set up a GridFS to access the database
\r
74 db = db_instance.get_database()
\r
75 fs = gridfs.GridFS(db)
\r
77 # try to find a file using the supplied robot_file_id
\r
78 compressed_file = fs.get(ObjectId(robot_file_id))
\r
80 # create the directories used during robot processing if they don't exist
\r
81 verify_directories()
\r
83 # generate a folder named by a uuid to organize data for each request
\r
84 random_uuid = uuid.uuid4().get_hex()
\r
85 data_dir = os.path.join(app.config['g_data_folder'], random_uuid)
\r
89 with open(os.path.join(data_dir, compressed_file.name), 'wb') as f:
\r
90 f.write(compressed_file.read().__str__())
\r
93 with zipfile.ZipFile(os.path.join(data_dir, compressed_file.name)) as zip_ref:
\r
94 # Create a temporary folder for storing extracted test file(s)
\r
95 test_dir = os.path.join(app.config['g_working_folder'], random_uuid)
\r
98 # Create a separate folder for the output files, so they can be compressed and sent back to the TCU
\r
99 test_output_dir = os.path.join(test_dir, 'output')
\r
100 os.mkdir(test_output_dir)
\r
102 # Extract the robot tests into the temporary directory
\r
103 zip_ref.extractall(test_dir)
\r
105 # Run the robot tests with the outputdir pointed to the temporary directory
\r
106 return_code = run(os.path.join(test_dir), outputdir=os.path.join(test_dir, 'output'))
\r
108 # this path is hardcoded so the entire system path isn't included in the zip
\r
109 path = './files/results/{uuid}/output'.format(uuid=random_uuid)
\r
110 zip_file = zipfile.ZipFile(path + '.zip', 'w', zipfile.ZIP_DEFLATED, allowZip64=True)
\r
111 zip_dir(path, zip_file)
\r
114 # save the results to the database
\r
115 zf = open(path + '.zip', 'rb')
\r
116 result_id = fs.put(zf, filename='output.zip', contentType='application/zip')
\r
119 response_data['vthResponse']['resultData']['robotStatusCode'] = return_code
\r
120 response_data['vthResponse']['resultData']['robotResultFileId'] = str(result_id)
\r
121 response_data['vthResponse']['abstractMessage'] = resolve_robot_status_code(return_code)
\r
125 # delete data from the local disk
\r
126 shutil.rmtree(path.replace('/output', ''))
\r
127 shutil.rmtree(data_dir)
\r
129 # record the end time of the test
\r
130 end_time = unix_time_millis(datetime.datetime.now())
\r
132 # Calculate the total duration of the test
\r
133 total_time = end_time - start_time
\r
135 # Set the test duration in the result
\r
136 response_data['vthResponse']['testDurationMS'] = total_time
\r
138 return jsonify(response_data)
\r
139 except NoFile as e:
\r
140 # this exception can only occur if robot_file_id is set to something, so don't worry about reference precedence.
\r
141 end_time = unix_time_millis(datetime.datetime.now())
\r
142 total_time = end_time - start_time
\r
144 response_data['vthResponse']['testDurationMS'] = ''
\r
145 response_data['vthResponse']['abstractMessage'] = \
\r
146 'An exception occurred after running for {totalTime} milliseconds. ' \
\r
147 'A file with _id {id} was not found in the collection.'.format(id=robot_file_id, totalTime=total_time)
\r
149 response = make_response(json.dumps(response_data))
\r
152 except Exception as e:
\r
153 app.logger.error(e)
\r
154 end_time = unix_time_millis(datetime.datetime.now())
\r
155 total_time = end_time - start_time
\r
157 response_data['vthResponse']['testDurationMS'] = ''
\r
158 response_data['vthResponse']['abstractMessage'] = \
\r
159 'An exception occurred after running for {totalTime} milliseconds. ' \
\r
160 'Exception: {exception}.'.format(exception=str(e), totalTime=total_time)
\r
162 response = make_response(json.dumps(response_data))
\r