Exam Administration¶
Lifecycle at a glance¶
The model is declarative: the instructor writes a single file, /var/lib/sre/exam.json, and the GUI on each student PC does the rest. Two invariants make this work:
exam.jsonis the trigger. Its presence puts the GUI in exam mode; its contents determine the current phase, the countdowns, and what to fire next. The instructor’s only job is to create, edit, or delete this file — viasre set-examandsre del-exam. The GUI polls it once per second and firespre-start-exam,start-exam,eval-exam, andend-examat the appropriate moments.Every exam command is idempotent. Each one can be re-run safely, which is what lets the GUI recover from transient failures and react to mid-exam edits. The instructor can extend the duration, add or remove a lab, or push back the end time at any point by editing
exam.json(viasre set-exam); the change propagates within one second.
[Instructor] [GUI on each student PC, polling exam.json @ 1 Hz]
│ │
│ sre set-exam --labs tp1 \ │
│ --start-after 09:00 \ │ ← exam.json appears
│ --end-before 11:00 \ │
│ --duration 120 │
│ --eval-interval 60 │
│ │
│ Phase: WAITING
│ • shows logo + countdown to 09:00
│ • ~60 s before start_after, sysreseval GUI fires
│ sre pre-start-exam (pulls images,
│ starts containers, writes pre_start_date)
│ │
├── 09:00 ──────────────────────────────►│
│ Phase: ACTIVE
│ • once projects are up, sysreseval GUI fires
│ sre start-exam (stamps started_at)
│ • shows remaining-time countdown
│ • fires sre eval-exam every 60 s
│ • student works, may self-grade
│ │
├── 11:00 (or started_at + 120 min) ────►│
│ Phase: ENDED
│ • sysreseval GUI fires sre end-exam once
│ (final concurrent eval + stamps ended_at)
│ • shows "That's All Folks"
│ │
│ sre del-exam │
│ (removes exam.json, wipes projects) │
| sre sheet / outline / re-eval │ ← post-exam grading
Setting up an exam — sre set-exam¶
# Minimal — one lab, hard end time. No start time means "open immediately".
sre set-exam --labs s4/tp_ssh --end-before 11:00
# With some more options example
sre set-exam \
--labs s4/tp_ssh s4/tp_dhcp:hard \
--start-after 2026-06-15T09:00 \
--end-before 2026-06-15T11:00 \
--duration 90 \
--eval-interval 30
In this case, each student gets 90 minutes, but every exam ends at 11:00 — even for students who start after 9:30.
Behaviour:
Incremental updates. Only the options provided on the command line are written; everything else is preserved.
sre set-exam --duration 150extends an in-progress exam without touchinglabsorstart_after.First-time requirements. If
exam.jsondoes not yet exist,--labsis required, and so is at least one of--end-before/--duration(otherwise the exam would never end).Date formats. Both
--start-afterand--end-beforeaccept full datetimes (2026-06-01T09:00,2026-06-01 09:00,2026-06-01T09:00:00) and time-only (09:00,09:00:00) — time-only is combined with today’s date.Lab validation. Each lab name is checked against
sre list(get_lab_list(include_exam_only_labs=True)); absolute paths must lie underparams.authorized_src_dir(/opt/sre/lab/or/home/admin1/, etc..).Resetting
start_afterresets state. Changing--start-afterclearspre_start_dateandstarted_atso the GUI re-triggerspre-start-examandstart-examfor the new run.Mis-exam edits. Anything in
exam.jsonmay be changed while the exam is running; the GUI picks up changes within 1 s.relative duration change. During an exam,
--duration +Xor--duration -Xadd or substract X minutes.
Option |
Effect |
|---|---|
|
Authorised labs; |
|
Exam opens after this moment. If omitted, the exam is considered open immediately. |
|
Exam closes after this moment, regardless of |
|
Hard cap on duration; the exam ends at |
|
Automatic-eval period (default 60). |
|
Record terminal sessions ( |
See Exam Reference for how the GUI drives the exam (phase computation and per-phase actions).
Monitoring an exam¶
Once each student machine mirrors its archives into a shared directory subtree on the instructor’s machine
(see the Installation chapter), sre watch <directory> provides a live dashboard of the exam:
Remaining time and latest grade per student.
Inactivity alerts when no new archive has appeared for a student in the last X seconds — usually a sign that
sysresevalcrashed or the machine was shut down.Evaluation-error alerts flagging any error raised by the last eval. A well-written lab should never produce errors; if a command is legitimately allowed to fail, pass
allow_error=TruetoGrade.cmd()so the failure is not reported.
The dashboard shows one row per running project instance (hostname, lab and start time), so a student
who opened the same lab twice gets two rows, each with its own grade and alerts, instead of one row whose
grade jumps between the two. A lab that was stopped and started again also keeps its old row, with an
inactivity alert, until you dismiss it (P key) or hide it (S key). To see a single row per student
and lab, the most recently started instance, run sre watch -L <directory> or press L in the dashboard.
See CLI Reference for the other options and keys.
Clean up after an exam¶
sre del-exam
Removes exam.json and wipes every running project. Archive directories are preserved.
Note: in exam mode, quitting the GUI does not stop the Docker containers (unlike normal mode), so the instructor can keep them running afterwards — for instance to re-run a corrected version of the project if a bug surfaces during the exam.
Exam-only labs¶
Lab names containing any substring from params.exam_only_affix = ["_EXAM_", "_OLD_", "_DRAFT_", "_TESTS_"] are hidden from sysreseval’s lab picker.
This is how you keep an exam lab invisible until it appears in exam.json:
/opt/sre/lab/s4/ssh_EXAM_final.py— hidden from listings, but allowed in--labs./opt/sre/lab/_DRAFT_/work_in_progress.py— hidden in any subdirectory whose name contains a flagged affix.
sre set-exam --labs ... and all the commands from privileged users (sre start...) accept hidden labs of course.
Post-exam workflow¶
Inspect a single archive¶
sre cat --grades --answers /var/lib/sre/archives/20260615110000_*.zst
Field option |
Shows |
|---|---|
|
Per-element grades, total grade, max |
|
Student answers (incl. login, hostname, fullname, email, exam timing) |
|
Errors raised during grading |
|
Raw test results per machine (large) |
|
Serialized |
|
List or extract files saved into the archive |
|
One JSON dict per file on stdout (script-friendly) |
Re-grade with a corrected project file¶
If a grading bug surfaces during the exam, fix-it and re-grade every archive:
sre re-eval -s /opt/sre/lab/_EXAM_/ssh_corrected.py \
-p corrected \
-d /tmp/regraded \
-r /home/a/results/
Output archives appear in /tmp/regraded/ with the corrected prefix. Use sre check-eval -s ... first to preview the diff without writing any file.
On a site with the web front-end, add --update-web (as root, on a pool host, on the archives under their original
names) so that the Archives page of the portal shows the corrected results too: see
Re-evaluated archives.
This only works if the corrected project file does not require any new command to be run on the virtual machines:
re-evaluation replays the grading logic against the test output already stored in the archive, so a command that was never
executed during the exam (say, ip route on m1) cannot be recovered after the fact. Within that limit, fixing a grading
bug post-exam is straightforward.
To preview the impact of the correction on a single archive without writing anything, use:
sre check-eval --srelab corrected_project.py archive_file
which prints the diff between the stored grades and the re-graded ones.
The overall grade is computed by the Grade0.mark_exo_eval() method, which can be overridden to rescale or cap the final mark.
For example, to multiply every mark by 1.1 and round up to the next 0.1, override mark_exo_eval() in the lab’s Grade class:
def mark_exo_eval(self):
if not self._grade_list or self._total_max == 0:
return None
import math
return min(
self._maximum_mark,
math.ceil(10 * 1.1 * self._maximum_mark * self._total_grade / self._total_max) / 10,
)
Per-student PDF reports + summary spreadsheet¶
To create per-student PDF reports and a grade spreadsheet:
sre outline \
-o /tmp/summary.ods \
-d /tmp/reports \
-r /var/lib/sre/archives/
Useful options:
--users-file <file>— auxiliaryLOGIN NAME EMAILfile (whitespace- or CSV-separated,#for comments) that supersedes the names and emails embedded in the archives. Handy when student logins are pseudonyms.--remaining-time— include each student’s remaining exam time (fromexam_time_remainingin the archive) in the summary.--no-timeline- omit the evaluation history table from PDF reports--no-parts- do not group PDF grade rows by GradePart (flat list, no subtotals)--separate-instances- one PDF report and one ODS row per running project instance instead of one per student. By default a student who opened the same lab several times gets a single report: the best grade is taken across all instances and the evaluation history shows one table per instance, headed by its start time. With this option each instance gets its own report (the PDF name ends with the instance start timestamp) and its own row in the summary, with aproject_startcolumn.
Export to a spreadsheet¶
To get a full sheet of all grades elements of all evaluations with per-question summary:
sre sheet -o /tmp/exam-results.ods -r /var/lib/sre/archives/
Each archive is one row of the lab’s sheet, with a project_start column identifying the running project
instance it comes from; rows are sorted by login, hostname, project start and evaluation date. The
Sessions sheet keeps the best score per student; add --separate-instances to get one line per running
project instance instead, for a student who opened the same lab several times.