@@ -23,7 +23,7 @@ use std::{
2323use askama:: Template ;
2424use askama_web:: WebTemplate ;
2525use crossbeam_channel:: { Receiver , Sender } ;
26- use jane_eyre:: eyre:: { self , eyre, Context , OptionExt } ;
26+ use jane_eyre:: eyre:: { self , bail , eyre, Context , OptionExt } ;
2727use mktemp:: Temp ;
2828use rocket:: {
2929 delete,
@@ -47,7 +47,10 @@ use web::{
4747use crate :: {
4848 dashboard:: Dashboard ,
4949 data:: { get_profile_data_path, get_runner_data_path, run_migrations} ,
50- github:: { list_registered_runners_for_host, Cache } ,
50+ github:: {
51+ download_artifact_string, list_registered_runners_for_host, list_workflow_run_artifacts,
52+ Cache ,
53+ } ,
5154 id:: IdGen ,
5255 image:: { start_libvirt_guest, Rebuilds } ,
5356 libvirt:: list_runner_guests,
@@ -230,6 +233,77 @@ fn take_runners_route(
230233 Ok ( RawJson ( result) )
231234}
232235
236+ #[ post( "/select-runner?<unique_id>&<qualified_repo>&<run_id>" ) ]
237+ fn select_runner_route (
238+ unique_id : String ,
239+ qualified_repo : String ,
240+ run_id : String ,
241+ ) -> rocket_eyre:: Result < RawJson < String > > {
242+ let artifacts = list_workflow_run_artifacts ( & qualified_repo, & run_id) ?;
243+ let done_artifact = format ! ( "servo-ci-runners_{unique_id}_done" ) ;
244+ if artifacts
245+ . iter ( )
246+ . find ( |artifact| artifact. name == done_artifact)
247+ . is_some ( )
248+ {
249+ Err ( EyreReport :: InternalServerError ( eyre ! (
250+ "Job has artifact marking it as done: {done_artifact}"
251+ ) ) ) ?;
252+ }
253+ let args_artifact = format ! ( "servo-ci-runners_{unique_id}" ) ;
254+ let Some ( args_artifact) = artifacts
255+ . into_iter ( )
256+ . find ( |artifact| artifact. name == args_artifact)
257+ else {
258+ Err ( EyreReport :: InternalServerError ( eyre ! (
259+ "No args artifact found: {args_artifact}"
260+ ) ) ) ?
261+ } ;
262+ let args_artifact = download_artifact_string ( & args_artifact. archive_download_url ) ?;
263+ let mut args = args_artifact
264+ . lines ( )
265+ . flat_map ( |line| line. split_once ( "=" ) )
266+ . collect :: < BTreeMap < & str , & str > > ( ) ;
267+ if args. remove ( "unique_id" ) != Some ( & * unique_id) {
268+ Err ( EyreReport :: InternalServerError ( eyre ! (
269+ "Wrong unique_id in artifact"
270+ ) ) ) ?;
271+ }
272+ if args. remove ( "qualified_repo" ) != Some ( & * qualified_repo) {
273+ Err ( EyreReport :: InternalServerError ( eyre ! (
274+ "Wrong qualified_repo in artifact"
275+ ) ) ) ?;
276+ }
277+ if args. remove ( "run_id" ) != Some ( & * run_id) {
278+ Err ( EyreReport :: InternalServerError ( eyre ! (
279+ "Wrong run_id in artifact"
280+ ) ) ) ?;
281+ }
282+ let Some ( profile_key) = args. remove ( "self_hosted_image_name" ) else {
283+ Err ( EyreReport :: InternalServerError ( eyre ! (
284+ "Wrong run_id in artifact"
285+ ) ) ) ?
286+ } ;
287+
288+ let ( response_tx, response_rx) = crossbeam_channel:: bounded ( 0 ) ;
289+ REQUEST . sender . send_timeout (
290+ Request :: TakeRunners {
291+ response_tx,
292+ profile_key : profile_key. to_owned ( ) ,
293+ query : TakeRunnerQuery {
294+ unique_id,
295+ qualified_repo,
296+ run_id,
297+ } ,
298+ count : 1 ,
299+ } ,
300+ DOTENV . monitor_thread_send_timeout ,
301+ ) ?;
302+ let result = response_rx. recv_timeout ( DOTENV . monitor_thread_recv_timeout ) ?;
303+
304+ Ok ( RawJson ( result) )
305+ }
306+
233307#[ get( "/policy/override" ) ]
234308fn get_override_policy_route ( ) -> rocket_eyre:: Result < Json < Option < Override > > > {
235309 let ( response_tx, response_rx) = crossbeam_channel:: bounded ( 0 ) ;
@@ -388,6 +462,7 @@ async fn main() -> eyre::Result<()> {
388462 dashboard_json_route,
389463 take_runner_route,
390464 take_runners_route,
465+ select_runner_route,
391466 get_override_policy_route,
392467 override_policy_route,
393468 delete_override_policy_route,
0 commit comments