def new_job(self, task, inputdata, callback, launcher_name="Unknown", debug=False, ssh_callback=None): """ Add a new job. Every callback will be called once and only once. :type task: Task :param inputdata: input from the student :type inputdata: Storage or dict :param callback: a function that will be called asynchronously in the client's process, with the results. it's signature must be (result, grade, problems, tests, custom, archive), where: result is itself a tuple containing the result string and the main feedback (i.e. ('success', 'You succeeded'); grade is a number between 0 and 100 indicating the grade of the users; problems is a dict of tuple, in the form {'problemid': result}; test is a dict of tests made in the container custom is a dict containing random things set in the container archive is either None or a bytes containing a tgz archive of files from the job :type callback: __builtin__.function or __builtin__.instancemethod :param launcher_name: for informational use :type launcher_name: str :param debug: Either True(outputs more info), False(default), or "ssh" (starts a remote ssh server. ssh_callback needs to be defined) :type debug: bool or string :param ssh_callback: a callback function that will be called with (host, port, password), the needed credentials to connect to the remote ssh server. May be called with host, port, password being None, meaning no session was open. :type ssh_callback: __builtin__.function or __builtin__.instancemethod or None :return: the new job id """ job_id = str(uuid.uuid4()) if debug == "ssh" and ssh_callback is None: self._logger.error("SSH callback not set in %s/%s", task.get_course_id(), task.get_id()) callback(("crash", "SSH callback not set."), 0.0, {}, {}, {}, None, "", "") return # wrap ssh_callback to ensure it is called at most once, and that it can always be called to simplify code ssh_callback = _callable_once(ssh_callback if ssh_callback is not None else lambda _1, _2, _3: None) environment = task.get_environment() if environment not in self._available_containers: self._logger.warning("Env %s not available for task %s/%s", environment, task.get_course_id(), task.get_id()) ssh_callback(None, None, None) # ssh_callback must be called once callback(("crash", "Environment not available."), 0.0, {}, {}, {}, None, "", "") return enable_network = task.allow_network_access_grading() try: limits = task.get_limits() time_limit = int(limits.get('time', 20)) hard_time_limit = int(limits.get('hard_time', 3 * time_limit)) mem_limit = int(limits.get('memory', 200)) except: self._logger.exception("Cannot retrieve limits for task %s/%s", task.get_course_id(), task.get_id()) ssh_callback(None, None, None) # ssh_callback must be called once callback(("crash", "Error while reading task limits"), 0.0, {}, {}, {}, None, "", "") return msg = ClientNewJob(job_id, task.get_course_id(), task.get_id(), inputdata, environment, enable_network, time_limit, hard_time_limit, mem_limit, debug, launcher_name) self._loop.call_soon_threadsafe(asyncio.ensure_future, self._create_transaction(msg, task=task, callback=callback, ssh_callback=ssh_callback)) return job_id
def new_job(self, priority, task, inputdata, callback, launcher_name="Unknown", debug=False, ssh_callback=None): """ Add a new job. Every callback will be called once and only once. :param priority: Priority of the job :type task: Task :param inputdata: input from the student :type inputdata: Storage or dict :param callback: a function that will be called asynchronously in the client's process, with the results. it's signature must be (result, grade, problems, tests, custom, archive), where: result is itself a tuple containing the result string and the main feedback (i.e. ('success', 'You succeeded'); grade is a number between 0 and 100 indicating the grade of the users; problems is a dict of tuple, in the form {'problemid': result}; test is a dict of tests made in the environment custom is a dict containing random things set in the environment archive is either None or a bytes containing a tgz archive of files from the job :type callback: __builtin__.function or __builtin__.instancemethod :param launcher_name: for informational use :type launcher_name: str :param debug: Either True(outputs more info), False(default), or "ssh" (starts a remote ssh server. ssh_callback needs to be defined) :type debug: bool or string :param ssh_callback: a callback function that will be called with (host, port, password), the needed credentials to connect to the remote ssh server. May be called with host, port, password being None, meaning no session was open. :type ssh_callback: __builtin__.function or __builtin__.instancemethod or None :return: the new job id, or None if an error happened """ job_id = str(uuid.uuid4()) safe_callback = _callable_once(callback) if debug == "ssh" and ssh_callback is None: self._logger.error("SSH callback not set in %s/%s", task.get_course_id(), task.get_id()) safe_callback(("crash", "SSH callback not set."), 0.0, {}, {}, {}, None, "", "") return None # wrap ssh_callback to ensure it is called at most once, and that it can always be called to simplify code ssh_callback = _callable_once(ssh_callback if ssh_callback is not None else lambda _1, _2, _3: None) environment = task.get_environment_id() if environment not in self._available_environments: self._logger.warning("Env %s not available for task %s/%s", environment, task.get_course_id(), task.get_id()) ssh_callback(None, None, None) # ssh_callback must be called once safe_callback(("crash", "Environment not available."), 0.0, {}, {}, "", {}, None, "", "") return None environment_type = task.get_environment_type() if self._available_environments[environment] != environment_type: self._logger.warning("Env %s does not have the expected type %s, but rather %s, in task %s/%s", environment, environment_type, self._available_environments[environment], task.get_course_id(), task.get_id()) ssh_callback(None, None, None) # ssh_callback must be called once safe_callback(("crash", "Environment {}-{} not available.".format(environment_type, environment)), 0.0, {}, {}, "", {}, None, "", "") return None environment_parameters = task.get_environment_parameters() msg = ClientNewJob(job_id, priority, task.get_course_id(), task.get_id(), task.get_problems_dict(), inputdata, environment, environment_parameters, debug, launcher_name) self._loop.call_soon_threadsafe(asyncio.ensure_future, self._create_transaction(msg, task=task, callback=safe_callback, ssh_callback=ssh_callback)) return job_id