def get(self, hostname_status, hostname): """GET request for information about hostname Args: hostname_status: binary representation of a retired system. hostname: string name of system hostname passed through url. Returns: Hostname data as represented in the hostnames table. Success: Status Code: 200 OK * return hostnames table entry. Failure: Status Code: 404 Not Found * hostname does not exist or invalid hostname_status. """ validate(hostname=hostname, hostname_status=hostname_status, http_error_code=404) # query for hostname information hostnames_list = get_table('hostnames', hostname=hostname, hostname_status=hostname_status) return {'hostnames': hostnames_list}, 200
def get(self, tests_runs_id, tests_logs_id): """Download test log file.""" validate(tests_runs_id=tests_runs_id, tests_logs_id=tests_logs_id) tests_log = get_data_by_id('tests_logs', tests_logs_id) if tests_runs_id != tests_log['tests_runs_id']: # invalid url - no log with under given tests_runs id error_msg = 'tests_runs_id=\'{}\' with tests_logs_id=\'{}\' Not Found.' abort(404, message=error_msg.format(tests_runs_id, tests_logs_id)) # absolute path to file log filepath = tests_log['location'] # unique name of file for log in disk uuid_filename = filepath.split('/')[-1] # path to folder that hold the log file in disk upload_folder = filepath.replace(uuid_filename, '') # user friendly name of test log friendly_filename = tests_log['files_name'] file_attachment = send_from_directory( upload_folder, uuid_filename, as_attachment=True, attachment_filename=friendly_filename) return file_attachment
def get(self, hostname_status, hostname): """GET request for all info on tests_runs associated with the hostname. Args: hostname: string name of system hostname passed through url. Returns: Table dictionary of tests_runs with applied query paramters for filtering. Success: Status Code: 200 OK * return tests runs information Failure: Status Code: 404 Not Found * Invalid url - invalid hostname_status or hostname """ validate(hostname_status=hostname_status, hostname=hostname, http_error_code=404) parser = reqparse.RequestParser() add_filter_query_parameters(parser, 'tests_runs') args = parser.parse_args() filter = parse_filter_query_parameters(args, 'tests_runs') # overwrite filter with static info from uri static_params = zip_params(hostname=hostname, hostname_status=hostname_status) filter.update(static_params) # query for filtered test-history tests_runs = get_table('tests_runs', constraints=filter) return {'tests_runs': tests_runs}, 200
def post(self, hostname_status): """POST request to add a hostname to the database. Args: hostname_status: string annotation of a system for a binary representation of an 'active' Returns: Dictionary of inserted hostname with keys coinciding column names of the table hostnames. Success: Status Code: 201 Created * hostname inserted into the database. Failure: Status Code: 404 Not Found * status provided does not exist. * required arguments not supplied in request. Status Code: 405 Method Not Allowed * attempt to add a non-active hostname not allowed. Status Code: 409 Conflict * duplicate insertion for active hostname not allowed. """ validate(hostname_status=hostname_status, http_error_code=404) # require 'hostname' parameter from request. parser = reqparse.RequestParser() parser.add_argument('hostname', type=str, required=True) args = parser.parse_args() if is_retired(hostname_status): # Hostnames added to the database must be active, return status code 405 Method Not Allowed return { 'message': 'The method is not allowed for the requested URL.' }, 405 # check if working hostname already exists in db. existing_hostname = get_table('hostnames', hostname=args['hostname'], hostname_status=hostname_status) if existing_hostname: # active hostname already exists, returning conflict status code 409. return { 'message': '{} hostname, {}, already exists. Insertion not allowed.'. format(hostname_status, args['hostname']) }, 409 # otherwise, insert hostname into db. inserted_hostname = insert_hostname(args['hostname']) return inserted_hostname
def post(self): """POST request to begin testrun on active 'hostname' with 'test'. Returns: Success: Status Code: 201 Created * inserted tests_runs dictionary row Failure: Status Code: 409 Conflict * hostname or test name supplied not found. * attempt to run a test on a retired hostname. """ parser = reqparse.RequestParser() parser.add_argument('hostname', type=str, required=True) parser.add_argument('tests_name', type=str, required=True) args = parser.parse_args() # validate that hostname and tests name exist in the db validate(hostname=args['hostname'], tests_name=args['tests_name'], http_error_code=409) # validate active hostname active_hostname = get_table('hostnames', hostname=args['hostname'], retiredflag=HOSTNAME_ACTIVE) if not active_hostname: # throw 409 Conflict error for attempt to run a test on a retired system error_msg = 'System \'{}\' must be active.'.format( args['hostname']) abort(409, message={'hostname': error_msg}) # if hostname has no running tests, directly execute test on hostname else queue test running_tests = get_running_tests(hostname=args['hostname']) # assume hostname is busy and queue test statuses_id = STATUS_QUEUED if not running_tests: # hostname server ready to directly host a test_run statuses_id = STATUS_STARTED inserted_tests_run = insert_tests_run(hostname=args['hostname'], tests_name=args['tests_name'], statuses_id=statuses_id) if statuses_id == STATUS_QUEUED: # insert to queue insert_tests_runs_queue(inserted_tests_run['id']) return inserted_tests_run, 201
def post(self, tests_runs_id): """POST request to upload a log associated with a testsrun. Args: tests_runs_id: integer representation of a unique testsrun passed thorugh url. """ validate(tests_runs_id=tests_runs_id, http_error_code=404) inserted_tests_logs = [] for a_file in request.files.getlist('file'): if a_file.filename: # insert file log to database and disk tests_logs_id = insert_tests_log(tests_runs_id, a_file) data = get_data_by_id('tests_logs', tests_logs_id, raw=True) inserted_tests_logs.append(data) return {'tests_logs' : inserted_tests_logs}, 201
def put(self, tests_runs_id): """Updates testsruns table row data. Returns: Dictionary of updated tests_runs row. Success: Status Code: 200 OK * tests_runs row is updated. Failure: Status Code: 404 Not Found * invalid url - tests_runs_id not found. * """ validate(tests_runs_id=tests_runs_id, http_error_code=404) # require status name parameter from request. parser = reqparse.RequestParser() parser.add_argument('statuses_name', type=str) parser.add_argument('config', type=str) parser.add_argument('notes', type=str) parser.add_argument('scratch', type=str) args = parser.parse_args() statuses = {} if args['statuses_name']: # get statuses full profile (id, name) validate(statuses_name=args['statuses_name'], http_error_code=409) data = get_table('statuses', statuses_name=args['statuses_name']) statuses = data[0] values = {} for field in get_table_fields('tests_runs'): # set up tests_runs fields to be updated with args if field in args and args[field]: values.update({field : args[field]}) elif field == 'statuses_id' and statuses: values.update({field : statuses['id']}) if not values: # no data to updated abort(400, message='At least one parameter is required: {}'.format(args.keys())) updated_tests_runs = update('tests_runs', tests_runs_id, values) return updated_tests_runs, 200
def get(self, tests_runs_id): """GET request for (hostname, tests name, start time, end time, notes, config, scratch) on testsrun with url passed 'id' Args: tests_runs_id : Integer identification of a specific testsrun in interest passed through url. Returns: Success: Status Code: 200 OK * table row dictionary from 'tests_runs' with row id = 'id'. Failure: Status Code: 404 Not Found * testsruns row 'id' does not exists in database. """ validate(tests_runs_id=tests_runs_id, http_error_code=404) tests_run = get_table('tests_runs', tests_runs_id=tests_runs_id) return tests_run
def delete(self, tests_runs_id): """Delete tests_log file from disk and db.""" validate(tests_runs_id=tests_runs_id, http_error_code=404) # require tests_logs_id paramter in POST body parser = reqparse.RequestParser() parser.add_argument('tests_logs_id', type=int, required=True) args = parser.parse_args() # validate tests logs id exists validate(tests_logs_id=args['tests_logs_id'], http_error_code=404) tests_log = get_data_by_id('tests_logs', args['tests_logs_id']) if tests_runs_id != tests_log['tests_runs_id']: # log id does not belong to tests_run - conflict error_msg = 'tests_runs_id=\'{}\' with tests_logs_id=\'{}\' Not Found.' abort(409, message=error_msg.format(tests_runs_id, args['tests_logs_id'])) # delete log from disk and db deleted_log = delete_tests_log(args['tests_logs_id']) return deleted_log
def get(self, hostname_status): """GET request for all systems labeled as given by the 'hostname_status' Args: hostname_status: string annotation of a system for a binary representation of an 'active' or 'retired' hostname. Returns: Dictoinary of the hostnames table with a filtered hostname_status. Success: Status Code: 200 OK * valid hostname_status provided. Failure: Status Code: 404 Not Found * hostname_status provided unknown - not {active, retired} - invalid url. """ validate(hostname_status=hostname_status, http_error_code=404) # Get all hostnames with given retired hostname status hostnames_table = get_table('hostnames', hostname_status=hostname_status) return {'hostnames': hostnames_table}, 200
def get(self, tests_runs_id): """GET request for tests_logs_ids that contain the fileblobs associated with testsruns_id""" validate(tests_runs_id=tests_runs_id, http_error_code=404) tests_logs = get_table('tests_logs', tests_runs_id=tests_runs_id, raw=True) return {'tests_logs' : tests_logs}, 200
def delete(self, hostname_status): """DELETE the hostname by setting the retired flag to True. Args: hostname_status: string annotation of a system to show retired status. Returns: Dictionary of deleted hostname with keys coinciding the column names of table hostnames. Success: Status Code: 200 OK * hostname deleted. Failure: Status Code: 404 Not Found * invalid url - hostname_status is not valid. Status Code: 400 Bad Request * no parameters were passed in the JSON body to the request. Status Code: 405 Method Not Allowed * attempt to do a DELETE request on invalid hostname_status in url Status Code: 409 Conflict * hostname did not exist in the database. * hostname is marked as retired in the database. * active hostname is busy with running tests. """ validate(hostname_status=hostname_status, http_error_code=404) if is_retired(hostname_status): # only remove active hostnames; return 405 Method Not Allowed return { 'message': 'The method is not allowed for the requested URL.' }, 405 # require 'hostname' parameter from request. parser = reqparse.RequestParser() parser.add_argument('hostname', type=str) parser.add_argument('hostnames_id', type=int) args = parser.parse_args() if args['hostname'] is None and args['hostnames_id'] is None: # at least one argument is required otherwise throw 400 Bad Request. errors = { 'hostname': 'Missing parameter in JSON body', 'hostnames_id': 'Missing parameter in JSON body', 'message': 'At least one paramter is required', } abort(400, message=errors) # validate that hostname info exists in the db validate(hostname=args['hostname'], hostnames_id=args['hostnames_id'], http_error_code=409) # validate that the hostname is active active_hostname = get_table('hostnames', hostname=args['hostname'], hostnames_id=args['hostnames_id'], hostname_status=hostname_status) if not active_hostname: # hostname is not active - validation check failed. supplied_args = { key: value for key, value in args.items() if value is not None } error_msg = 'No active hostname found with supplied args: {}'.format( supplied_args) abort(409, message=error_msg) # if hostname is running tests - abort DELETE request running_tests = get_running_tests(hostname=args['hostname'], hostnames_id=args['hostnames_id']) if running_tests: # system currently running tests - throw 409 Conflict error_msg = 'System is Busy. Currently processing {} tests.'.format( len(running_tests)) errors = {args['hostname']: error_msg} abort(409, message=errors) # internally hostnames_id takes precedence over hostname string hostnames_deleted = delete_hostname(hostnames_id=args['hostnames_id'], hostname=args['hostname']) return {'hostnames': hostnames_deleted}, 200