Astprocd

Astprocd is responsible for:

  • Waiting for usercode drive information from Astdiskd

  • Starting and managing the Usercode Lifecycle

  • Writing logs to the usercode drive

  • Making logs available to other components in real time (To be implemented)

Usercode Lifecycle

When a new USB is inserted, it will follow the usercode lifecycle. The possible states of the lifecycle are defined in astoria.common.code_status.CodeStatus.

digraph {
   "None" -> "STARTING" [ label="USB Inserted", color="darkgreen"]
   "STARTING" -> "RUNNING" [ label="robot.zip valid", color="darkgreen" ]
   "STARTING" -> "CRASHED" [ label="robot.zip invalid", color="firebrick3" ]
   "STARTING" -> "CRASHED" [ label="proc start fail", color="firebrick3" ]
   "RUNNING" -> "CRASHED" [ label="proc exit. rc > 0", color="gold"]
   "RUNNING" -> "KILLED" [ label="proc exit. rc < 0", color="orange1" ]
   "RUNNING" -> "FINISHED" [ label="proc exit. rc = 0", color="darkgreen" ]
   "CRASHED" -> "STARTING" [ label="restart", color="violetred4" ]
   "KILLED" -> "STARTING" [ label="restart", color="violetred4" ]
   "FINISHED" -> "STARTING" [ label="restart", color="violetred4" ]
}

It is only possible for one usercode lifecycle to exist at any one time, so additional usercode USBs will be ignored if there is already a lifecycle in progress. This is the case even if the lifecycle exists in one of the stopped states.

Usercode can be executed multiple times within the lifecycle via the restart paths in the above diagram. A restart can only be triggered via mutation request.

Usercode Process Management

Usercode is executed as a child process of the astprocd process. This is managed via the asyncio.subprocess module, specifically asyncio.subprocess.Process.

  • The usercode process is started as a child process

  • The logger task captures stderr and stdout and writes to the log locations

  • SIGCHLD is received and return code handled.

  • The temporary directory is cleaned up.

Code is killed if USB is removed or by request. This manifests as a negative return code from the process.

Usercode is killed by sending SIGTERM, waiting 5 seconds and then sending SIGKILL if the process still exists.

Astprocd Data Structures and Classes

class astoria.common.code_status.CodeStatus(value)[source]

Status of the running code.

CRASHED = 'code_crashed'
FINISHED = 'code_finished'
KILLED = 'code_killed'
RUNNING = 'code_running'
STARTING = 'code_starting'
class astoria.common.ipc.ProcessManagerMessage(**data)[source]

Status message for Process Manager.

Published to astoria/astprocd

code_status: Optional[CodeStatus]
disk_info: Optional[DiskInfo]
pid: Optional[int]
class astoria.astprocd.ProcessManager(verbose, config_file)[source]

Astoria Process State Manager.

dependencies = ['astdiskd', 'astmetad']
async handle_disk_insertion(uuid, disk_info)[source]

Handle a disk insertion.

Return type:

None

async handle_disk_removal(uuid, disk_info)[source]

Handle a disk removal.

Return type:

None

async handle_kill_request(request)[source]

Handle a request to kill running usercode.

Return type:

RequestResponse

async handle_metadata(metadata)[source]

Handle a metadata update.

Return type:

None

async handle_restart_request(request)[source]

Handle a request to restart usercode.

Return type:

RequestResponse

async main()[source]

Main routine for astprocd.

Return type:

None

name = 'astprocd'
property offline_status: ProcessManagerMessage

Status to publish when the manager goes offline.

This status should ensure that any other components relying on this data go into a safe state.

update_status(code_status=None)[source]

Calculate and update the status of this manager.

Called by the usercode lifecycle to inform us of changes.

Return type:

None