def execute(work_item, session, background=False): # type: (WorkItem, Session, bool) -> Dict[str, Any] """Submit a work item to Batfish. :param work_item: work to submit :type work_item: :py:class:`~pybatfish.client.WorkItem` :param session: Batfish session to use. :type session: :py:class:`~pybatfish.client.session.Session` :param background: Whether to background the job. If `True`, this function only returns the result of submitting the job. :type background: bool :return: If `background=True`, a dict containing a single key 'result' with a string description of the result. If `background=False`, a dict containing a single key 'status' with a string describing work status. """ snapshot = work_item.requestParams.get(BfConsts.ARG_TESTRIG) if snapshot is None: raise ValueError('Work item {} does not include a snapshot name'.format( work_item.to_json())) json_data = { CoordConsts.SVC_KEY_WORKITEM: work_item.to_json(), CoordConsts.SVC_KEY_API_KEY: session.apiKey, } # Submit the work item response = resthelper.get_json_response( session, CoordConsts.SVC_RSC_QUEUE_WORK, json_data) if background: # TODO: this is ugly and messes with return types: design and write async replacement # After we drop 2.7 support return {"result": str(response["result"])} try: answer = get_work_status(work_item.id, session) status = WorkStatusCode(answer[CoordConsts.SVC_KEY_WORKSTATUS]) task_details = answer[CoordConsts.SVC_KEY_TASKSTATUS] while not WorkStatusCode.is_terminated(status): print_work_status(session, status, task_details) time.sleep(1) answer = get_work_status(work_item.id, session) status = WorkStatusCode(answer[CoordConsts.SVC_KEY_WORKSTATUS]) task_details = answer[CoordConsts.SVC_KEY_TASKSTATUS] print_work_status(session, status, task_details) if status == WorkStatusCode.ASSIGNMENTERROR: raise BatfishException( "Work finished with status {}\n{}".format(status, work_item.to_json())) return {"status": status} except KeyboardInterrupt: response = kill_work(session, work_item.id) raise KeyboardInterrupt( "Killed ongoing work: {}. Server response: {}".format( work_item.id, json.dumps(response)))
def execute(work_item, session, background=False, extra_args=None): # type: (WorkItem, Session, bool, Optional[Dict[str, Any]]) -> Dict[str, Any] """Submit a work item to Batfish. :param work_item: work to submit :type work_item: :py:class:`~pybatfish.client.WorkItem` :param session: Batfish session to use. :type session: :py:class:`~pybatfish.client.session.Session` :param background: Whether to background the job. If `True`, this function only returns the result of submitting the job. :type background: bool :param extra_args: extra arguments to be passed to Batfish. :type extra_args: dict :return: If `background=True`, a dict containing a single key 'result' with a string description of the result. If `background=False`, a dict containing a single key 'status' with a string describing work status. """ if extra_args is not None: work_item.requestParams.update(extra_args) snapshot = work_item.requestParams.get(BfConsts.ARG_TESTRIG) if snapshot is None: raise ValueError( "Work item {} does not include a snapshot name".format( work_item.to_json())) json_data = { CoordConsts.SVC_KEY_WORKITEM: work_item.to_json(), CoordConsts.SVC_KEY_API_KEY: session.api_key, } # Submit the work item response = resthelper.get_json_response(session, CoordConsts.SVC_RSC_QUEUE_WORK, json_data) if background: # TODO: this is ugly and messes with return types: design and write async replacement # After we drop 2.7 support return {"result": str(response["result"])} answer = get_work_status(work_item.id, session) status = WorkStatusCode(answer[CoordConsts.SVC_KEY_WORKSTATUS]) task_details = answer[CoordConsts.SVC_KEY_TASKSTATUS] cur_sleep = 0.1 # seconds while not WorkStatusCode.is_terminated(status): _print_work_status(session, status, task_details) time.sleep(cur_sleep) cur_sleep = min(1.0, cur_sleep * 1.5) answer = get_work_status(work_item.id, session) status = WorkStatusCode(answer[CoordConsts.SVC_KEY_WORKSTATUS]) task_details = answer[CoordConsts.SVC_KEY_TASKSTATUS] _print_work_status(session, status, task_details) # Handle fail conditions not producing logs if status in [ WorkStatusCode.ASSIGNMENTERROR, WorkStatusCode.REQUEUEFAILURE ]: raise BatfishException( "Work finished with status {}\nwork_item: {}\ntask_details: {}". format(status, work_item.to_json(), json.loads(task_details))) # Handle fail condition with logs if status == WorkStatusCode.TERMINATEDABNORMALLY: log = restv2helper.get_work_log(session, snapshot, work_item.id) log_file_msg = "" if len(log) > MAX_LOG_LENGTH: log_file = tempfile.NamedTemporaryFile().name with open(log_file, "w") as log_file_handle: log_file_handle.write(str(log)) log_file_msg = "Full log written to {}\n".format(log_file) raise BatfishException( "Work terminated abnormally\nwork_item: {item}\n\n{msg}log: {prefix}{log}" .format( item=work_item.to_json(), msg=log_file_msg, log=log[-MAX_LOG_LENGTH:], prefix="..." if log_file_msg else "", )) return {"status": status}
def execute(work_item, session, background=False): # type: (WorkItem, Session, bool) -> Dict[str, str] """Submit a work item to Batfish. :param work_item: work to submit :type work_item: :py:class:`~pybatfish.client.WorkItem` :param session: Batfish session to use. :type session: :py:class:`~pybatfish.client.session.Session` :param background: Whether to background the job. If `True`, this function only returns the result of submitting the job. :type background: bool :return: If `background=True`, a dict containing a single key 'result' with a string description of the result. If `background=False`, a dict containing "status" and "answer" keys, both strings. """ json_data = { CoordConsts.SVC_KEY_WORKITEM: work_item.to_json(), CoordConsts.SVC_KEY_API_KEY: session.apiKey } # Submit the work item response = resthelper.get_json_response(session, CoordConsts.SVC_RSC_QUEUE_WORK, json_data) if background: return {"result": str(response["result"])} try: answer = get_work_status(work_item.id, session) status = WorkStatusCode(answer[CoordConsts.SVC_KEY_WORKSTATUS]) task_details = answer[CoordConsts.SVC_KEY_TASKSTATUS] while not WorkStatusCode.is_terminated(status): print_work_status(session, status, task_details) time.sleep(1) answer = get_work_status(work_item.id, session) status = WorkStatusCode(answer[CoordConsts.SVC_KEY_WORKSTATUS]) task_details = answer[CoordConsts.SVC_KEY_TASKSTATUS] print_work_status(session, status, task_details) if status == WorkStatusCode.ASSIGNMENTERROR: raise BatfishException("Work finished with status {}\n{}".format( status, work_item.to_json())) # get the answer answer_file_name = _compute_batfish_answer_file_name(work_item) answer_bytes = resthelper.get_object(session, answer_file_name) # In Python 3.x, answer needs to be decoded before it can be used # for things like json.loads (<= 3.6). if six.PY3: answer_string = answer_bytes.decode(encoding="utf-8") else: answer_string = answer_bytes return {"status": status, "answer": answer_string} except KeyboardInterrupt: response = kill_work(session, work_item.id) raise KeyboardInterrupt( "Killed ongoing work: {}. Server response: {}".format( work_item.id, json.dumps(response)))