def clks_uploaded_to_project(project_id, check_data_ready=False): """ See if the given project has had all parties contribute data. """ logger.info("Counting contributing parties") conn = connect_db() if check_data_ready: parties_contributed = get_number_parties_ready(conn, project_id) logger.info("Parties where data is ready: {}".format(parties_contributed)) else: parties_contributed = get_number_parties_uploaded(conn, project_id) logger.info("Parties where data is uploaded: {}".format(parties_contributed)) number_parties = get_project_column(conn, project_id, 'parties') logger.info("{}/{} parties have contributed clks".format(parties_contributed, number_parties)) return parties_contributed == number_parties
def post(project_id, run): log = logger.bind(pid=project_id) log.debug("Processing request to add a new run", run=run) # Check the resource exists abort_if_project_doesnt_exist(project_id) # Check the caller has a valid results token. Yes it should be renamed. abort_if_invalid_results_token(project_id, request.headers.get('Authorization')) abort_if_project_in_error_state(project_id) run_model = Run.from_json(run, project_id) log.debug("Saving run") with db.DBConn() as db_conn: run_model.save(db_conn) project_object = db.get_project(db_conn, project_id) parties_contributed = db.get_number_parties_uploaded( db_conn, project_id) ready_to_run = parties_contributed == project_object['parties'] log.debug( "Expecting {} parties to upload data. Have received {}".format( project_object['parties'], parties_contributed)) if ready_to_run: log.info( "Scheduling task to carry out all runs for project {} now". format(project_id)) update_run_mark_queued(db_conn, run_model.run_id) else: log.info("Task queued but won't start until CLKs are all uploaded") if ready_to_run: span = g.flask_tracer.get_span() span.set_tag("run_id", run_model.run_id) span.set_tag("project_id", run_model.project_id) check_for_executable_runs.delay(project_id, serialize_span(span)) return RunDescription().dump(run_model), 201
def project_get(project_id): """ This endpoint describes a Project. """ log = logger.bind(pid=project_id) log.info("Getting detail for a project") abort_if_project_doesnt_exist(project_id) authorise_get_request(project_id) with DBConn() as db_conn: project_object = db.get_project(db_conn, project_id) # Expose the number of data providers who have uploaded clks parties_contributed = db.get_number_parties_uploaded( db_conn, project_id) num_parties_with_error = db.get_encoding_error_count( db_conn, project_id) log.info(f"{parties_contributed} parties have contributed hashes") project_object['parties_contributed'] = parties_contributed if num_parties_with_error > 0: log.warning( f"There are {num_parties_with_error} parties in error state") project_object['error'] = num_parties_with_error > 0 return ProjectDescription().dump(project_object)
def get(project_id, run_id): log = logger.bind(pid=project_id, rid=run_id) parent_span = g.flask_tracer.get_span() log.debug("request run status") with opentracing.tracer.start_span('check-auth', child_of=parent_span) as span: # Check the project and run resources exist abort_if_run_doesnt_exist(project_id, run_id) # Check the caller has a valid results token. Yes it should be renamed. auth_token_type = get_authorization_token_type_or_abort( project_id, request.headers.get('Authorization')) log.debug( "Run status authorized using {} token".format(auth_token_type)) with opentracing.tracer.start_span('get-status-from-db', child_of=parent_span) as span: dbinstance = get_db() run_status = db.get_run_status(dbinstance, run_id) project_in_error = db.get_encoding_error_count(dbinstance, project_id) > 0 span.set_tag('stage', run_status['stage']) run_type = RUN_TYPES[run_status['type']] state = 'error' if project_in_error else run_status['state'] stage = run_status['stage'] status = { "state": state, "time_added": run_status['time_added'], "stages": run_type['stages'], "current_stage": { "number": stage, "description": run_type['stage_descriptions'].get( stage, "there is no description for this stage") } } # trying to get progress if available if stage == 1: # waiting for CLKs abs_val = db.get_number_parties_uploaded(dbinstance, project_id) max_val = db.get_project_column(dbinstance, project_id, 'parties') elif stage == 2: # Computing similarity abs_val = cache.get_progress(run_id) if abs_val is not None: max_val = db.get_total_comparisons_for_project( dbinstance, project_id) else: # Solving for mapping (no progress) abs_val = None if abs_val is not None: progress = { 'absolute': abs_val, 'relative': (abs_val / max_val) if max_val != 0 else 0, } if progress['relative'] > 1.0: log.warning('oh no. more than 100% ??? abs: {}, max: {}'.format( abs_val, max_val)) if run_status['stage'] in run_type['stage_progress_descriptions']: progress['description'] = run_type['stage_progress_descriptions'][ run_status['stage']] status["current_stage"]["progress"] = progress if state == 'completed': status["time_started"] = run_status['time_started'] status["time_completed"] = run_status['time_completed'] return completed().dump(status) elif state == 'running' or state == 'queued' or state == 'created': status["time_started"] = run_status['time_started'] return running().dump(status) elif state == 'error': log.warning( 'handling the run status for state "error" is not implemented') return error().dump(status)