Source code for inginious.common.messages

# -*- coding: utf-8 -*-
#
# This file is part of INGInious. See the LICENSE and the COPYRIGHTS files for
# more information about the licensing of this file.
from typing import Dict, Optional, Any, Union, Tuple, List

from inginious.common.message_meta import MessageMeta

# JobId of the backend, composed with the adress of the client and the client job id
BackendJobId = Tuple[bytes, str]
ClientJobId = str
SPResult = Tuple[str, str]


#################################################################
#                                                               #
#                      Client to Backend                        #
#                                                               #
#################################################################


[docs]class ClientHello(metaclass=MessageMeta, msgtype="client_hello"): """ Let the client say hello to the backend (and thus register to some events) """ def __init__(self, name: str): """ :param name: name of the client (do not need to be unique) """ self.name = name
[docs]class ClientNewJob(metaclass=MessageMeta, msgtype="client_new_job"): """ Creates a new job B->A. """ def __init__(self, job_id: ClientJobId, course_id: str, task_id: str, inputdata: Dict[str, Any], environment: str, enable_network: bool, time_limit: int, hard_time_limit: Optional[int], mem_limit: int, debug: Union[str, bool], launcher: str): """ :param job_id: the client-side job id that is associated to this job :param course_id: course id of the task to run :param task_id: task id of the task to run :param inputdata: student input data :param environment: environment to use :param enable_network: wheter to enable the network or not, in supporting envs :param time_limit: timeout, in seconds, of the task, for supporting envs :param hard_time_limit: timeout, in seconds, of the task, for supporting envs. (hard) :param mem_limit: memory limit in Mo, for supporting envs. :param debug: True to enable debug False to disable it "ssh" to enable ssh debug :param launcher: the name of the entity that launched this job, for logging purposes """ self.job_id = job_id self.course_id = course_id self.task_id = task_id self.inputdata = inputdata self.debug = debug self.environment = environment self.enable_network = enable_network self.time_limit = time_limit self.hard_time_limit = hard_time_limit self.mem_limit = mem_limit self.launcher = launcher
[docs]class ClientKillJob(metaclass=MessageMeta, msgtype="client_kill_job"): """ Kills a running job. B->A. """ def __init__(self, job_id: ClientJobId): """ :param job_id: the client-side job id that is associated to the job to kill """ self.job_id = job_id
[docs]class ClientGetQueue(metaclass=MessageMeta, msgtype="client_get_queue"): """ Ask the backend to send the status of its job queue """ def __init__(self): pass
################################################################# # # # Backend to Client # # # #################################################################
[docs]class BackendUpdateContainers(metaclass=MessageMeta, msgtype="backend_update_containers"): """ Update the information about the containers on the client, from the informations retrieved from the agents """ def __init__(self, available_containers: Tuple[str]): """ :param available_containers: list of available container aliases """ self.available_containers = available_containers
[docs]class BackendJobStarted(metaclass=MessageMeta, msgtype="backend_job_started"): """ Indicates to the backend that a job started """ def __init__(self, job_id: ClientJobId): """ :param job_id: the client-side job_id associated to the job """ self.job_id = job_id
[docs]class BackendJobDone(metaclass=MessageMeta, msgtype="backend_job_done"): """ Gives the result of a job. """ def __init__(self, job_id: ClientJobId, result: SPResult, grade: float, problems: Dict[str, SPResult], tests: Dict[str, Any], custom: Dict[str, Any], archive: Optional[bytes], stdout: Optional[str], stderr: Optional[str]): """ :param job_id: the client-side job id associated with this job :param result: A tuple containing the result type and the text to be shown to the student Result type can be: - "killed": the container was killed externally (not really an error) - "crash": the container crashed (INGInious error) - "overflow": the container was killed due to a memory overflow (student/task writer error) - "timeout": the container was killed due to a timeout (student/task writer error) - "success": the student succeeded to resolve this task - "failed": the student failed to succeed this task - "error": an error happenned in the grading script (task writer error) :param grade: grade :param problems: particular feedbacks for each subproblem. Keys are subproblem ids. :param tests: tests made in the container :param custom: custom values :param archive: bytes string containing an archive of the content of the container as a tgz :param stdout: container stdout :param stderr: container stderr """ self.job_id = job_id self.result = result self.grade = grade self.problems = problems self.tests = tests self.custom = custom self.archive = archive self.stdout = stdout self.stderr = stderr
[docs]class BackendJobSSHDebug(metaclass=MessageMeta, msgtype="backend_job_ssh_debug"): """ Gives the necessary info to SSH into a job running in ssh debug mode """ def __init__(self, job_id: ClientJobId, host: str, port: int, password: str): """ :param job_id: the client-side job id associated with this job :param host: host to which the client should connect :param port: port on which sshd is bound :param password: password that allows to connect to the container """ self.job_id = job_id self.host = host self.port = port self.password = password
[docs]class BackendGetQueue(metaclass=MessageMeta, msgtype="backend_get_queue"): """ Send the status of the job queue to the client """ def __init__(self, jobs_running: List[Tuple[ClientJobId, bool, str, str, str, int, int]], jobs_waiting: List[Tuple[ClientJobId, bool, str, str, int]]): """ :param jobs_running: a list of tuples in the form (job_id, is_current_client_job, info, launcher, started_at, max_end) where - job_id is a job id. It may be from another client. - is_current_client_job is a boolean indicating if the client that asked the request has started the job - agent_name is the agent name - info is "courseid/taskid" - launcher is the name of the launcher, which may be anything - started_at the time (in seconds since UNIX epoch) at which the job started - max_end the time at which the job will timeout (in seconds since UNIX epoch), or -1 if no timeout is set :param jobs_waiting: a list of tuples in the form (job_id, is_current_client_job, info, launcher, max_time) where - job_id is a job id. It may be from another client. - is_current_client_job is a boolean indicating if the client that asked the request has started the job - info is "courseid/taskid" - launcher is the name of the launcher, which may be anything - max_time the maximum time that can be used, or -1 if no timeout is set """ self.jobs_running = jobs_running self.jobs_waiting = jobs_waiting
################################################################# # # # Backend to Agent # # # #################################################################
[docs]class BackendNewJob(metaclass=MessageMeta, msgtype="backend_new_job"): """ Creates a new job B->A. """ def __init__(self, job_id: BackendJobId, course_id: str, task_id: str, inputdata: Dict[str, Any], environment: str, enable_network: bool, time_limit: int, hard_time_limit: Optional[int], mem_limit: int, debug: Union[str, bool]): """ :param job_id: the backend-side job id that is associated to this job :param course_id: course id of the task to run :param task_id: task id of the task to run :param inputdata: student input data :param environment: environment to use :param enable_network: wheter to enable the network or not, in supporting envs :param time_limit: timeout, in seconds, of the task, for supporting envs :param hard_time_limit: timeout, in seconds, of the task, for supporting envs. (hard) :param mem_limit: memory limit in Mo, for supporting envs. :param debug: True to enable debug False to disable it "ssh" to enable ssh debug """ self.job_id = job_id self.course_id = course_id self.task_id = task_id self.inputdata = inputdata self.debug = debug self.environment = environment self.enable_network = enable_network self.time_limit = time_limit self.hard_time_limit = hard_time_limit self.mem_limit = mem_limit
[docs]class BackendKillJob(metaclass=MessageMeta, msgtype="backend_kill_job"): """ Kills a running job. B->A. """ def __init__(self, job_id: BackendJobId): """ :param job_id: the backend-side job id that is associated to the job to kill """ self.job_id = job_id
################################################################# # # # Agent to Backend # # # #################################################################
[docs]class AgentHello(metaclass=MessageMeta, msgtype="agent_hello"): """ Let the agent say hello and announce which containers it has available """ def __init__(self, friendly_name: str, available_job_slots: int, available_containers: Dict[str, Dict[str, str]]): """ :param friendly_name: a string containing a friendly name to identify agent :param available_job_slots: an integer giving the number of concurrent :param available_containers: dict of available containers { "name": { #for example, "default" "id": "container img id", # "sha256:715c5cb5575cdb2641956e42af4a53e69edf763ce701006b2c6e0f4f39b68dd3" "created": 12345678 # create date } } """ self.friendly_name = friendly_name self.available_job_slots = available_job_slots self.available_containers = available_containers
[docs]class AgentJobStarted(metaclass=MessageMeta, msgtype="agent_job_started"): """ Indicates to the backend that a job started A->B. """ def __init__(self, job_id: BackendJobId): """ :param job_id: the backend-side job_id associated to the job """ self.job_id = job_id
[docs]class AgentJobDone(metaclass=MessageMeta, msgtype="agent_job_done"): """ Gives the result of a job. A->B. """ def __init__(self, job_id: BackendJobId, result: SPResult, grade: float, problems: Dict[str, SPResult], tests: Dict[str, Any], custom: Dict[str, Any], archive: Optional[bytes], stdout: Optional[str], stderr: Optional[str]): """ :param job_id: the backend-side job id associated with this job :param result: a tuple that contains the result itself, either: - "killed": the container was killed externally (not really an error) - "crash": the container crashed (INGInious error) - "overflow": the container was killed due to a memory overflow (student/task writer error) - "timeout": the container was killed due to a timeout (student/task writer error) - "success": the student succeeded to resolve this task - "failed": the student failed to succeed this task - "error": an error happenned in the grading script (task writer error) and the feedback text. :param grade: grade :param problems: particular feedbacks for each subproblem. Keys are subproblem ids :param tests: tests made in the container :param custom: custom values :param archive: bytes string containing an archive of the content of the container as a tgz :param stdout: container stdout :param stderr : container stderr """ self.job_id = job_id self.result = result self.grade = grade self.problems = problems self.tests = tests self.custom = custom self.archive = archive self.stdout = stdout self.stderr = stderr
[docs]class AgentJobSSHDebug(metaclass=MessageMeta, msgtype="agent_job_ssh_debug"): """ Gives the necessary info to SSH into a job running in ssh debug mode """ def __init__(self, job_id: BackendJobId, host: str, port: int, password: str): """ :param job_id: the backend-side job id associated with this job :param host: host to which the client should connect :param port: port on which sshd is bound :param password: password that allows to connect to the container """ self.job_id = job_id self.host = host self.port = port self.password = password
################################################################# # # # Heartbeat # # # #################################################################
[docs]class Ping(metaclass=MessageMeta, msgtype="ping"): """ Ping message """ def __init__(self): pass
[docs]class Pong(metaclass=MessageMeta, msgtype="pong"): """ Pong message """ def __init__(self): pass
[docs]class Unknown(metaclass=MessageMeta, msgtype="unknown"): """ Unknown message. Sent by a server that do not know a specific client; probably because the server restarted """ def __init__(self): pass