@@ -40,6 +40,16 @@ pub(crate) enum SubCommand {
4040 command : PlacementSubCommand ,
4141 } ,
4242
43+ /// Inspect the resolved route for one run shard
44+ Route {
45+ /// Run UUID
46+ run_id : String ,
47+
48+ /// Logical run shard
49+ #[ arg( value_parser = clap:: value_parser!( i16 ) . range( 0 ..=127 ) ) ]
50+ run_shard : i16 ,
51+ } ,
52+
4353 /// Move one run shard to another database placement
4454 Move {
4555 /// Run UUID
@@ -160,6 +170,9 @@ impl Executable for Command {
160170 . await
161171 }
162172 SubCommand :: Placements { command } => exec_placement_command ( context, command) . await ,
173+ SubCommand :: Route { run_id, run_shard } => {
174+ exec_route_command ( context, run_id, run_shard) . await
175+ }
163176 }
164177 }
165178}
@@ -239,6 +252,28 @@ async fn exec_move_command(
239252 Ok ( ( ) )
240253}
241254
255+ async fn exec_route_command (
256+ context : Context ,
257+ run_id : String ,
258+ run_shard : i16 ,
259+ ) -> anyhow:: Result < ( ) > {
260+ let run_id = parse_run_id ( & run_id) ?;
261+ let database = context. db ( ) . await ?;
262+ let out = context. out ( ) . await ?;
263+ let route = shard_admin:: inspect_shard_route ( database, run_id, run_shard) . await ?;
264+
265+ info ! (
266+ run_id = %run_id,
267+ run_shard,
268+ database_alias = %route. database_alias,
269+ placement_status = %route. shard_placement_status,
270+ routing_decision = route. routing_decision,
271+ "inspected shard route"
272+ ) ;
273+ out. write_value ( & route_payload ( & route) ) ?;
274+ Ok ( ( ) )
275+ }
276+
242277async fn exec_placement_command (
243278 context : Context ,
244279 command : PlacementSubCommand ,
@@ -378,6 +413,24 @@ fn move_payload(outcome: &shard_admin::ShardMoveOutcome) -> Value {
378413 } )
379414}
380415
416+ fn route_payload ( route : & shard_admin:: ShardRouteInspection ) -> Value {
417+ json ! ( {
418+ "data" : {
419+ "run_id" : route. run_id,
420+ "run_shard" : route. run_shard,
421+ "database_alias" : route. database_alias,
422+ "shard_placement_status" : route. shard_placement_status,
423+ "database_role" : route. database_role,
424+ "database_status" : route. database_status,
425+ "database_url_env" : route. database_url_env,
426+ "database_url_env_resolved" : route. database_url_env_resolved,
427+ "dispatchable" : route. dispatchable,
428+ "readable" : route. readable,
429+ "routing_decision" : route. routing_decision,
430+ }
431+ } )
432+ }
433+
381434#[ cfg( test) ]
382435mod tests {
383436 use chrono:: Utc ;
@@ -442,6 +495,23 @@ mod tests {
442495 assert_eq ! ( alias, "shard_001" ) ;
443496 }
444497
498+ #[ test]
499+ fn route_command_matches_argument_shape ( ) {
500+ let run_id = Uuid :: now_v7 ( ) . to_string ( ) ;
501+ let cli = TestCli :: try_parse_from ( [ "vigilo" , "route" , & run_id, "4" ] ) . unwrap ( ) ;
502+
503+ let SubCommand :: Route {
504+ run_id : parsed_run_id,
505+ run_shard,
506+ } = cli. command
507+ else {
508+ panic ! ( "expected shard route command" ) ;
509+ } ;
510+
511+ assert_eq ! ( parsed_run_id, run_id) ;
512+ assert_eq ! ( run_shard, 4 ) ;
513+ }
514+
445515 #[ test]
446516 fn database_list_payload_reports_count ( ) {
447517 let placement = DatabasePlacement {
@@ -531,4 +601,39 @@ mod tests {
531601 assert_eq ! ( payload[ "meta" ] [ "verified" ] , json!( true ) ) ;
532602 assert_eq ! ( payload[ "data" ] [ "tables" ] [ 0 ] [ "table" ] , json!( "run_chunks" ) ) ;
533603 }
604+
605+ #[ test]
606+ fn route_payload_excludes_secret_url_value ( ) {
607+ let run_id = Uuid :: now_v7 ( ) ;
608+ let route = shard_admin:: ShardRouteInspection {
609+ run_id,
610+ run_shard : 4 ,
611+ database_alias : "shard_001" . to_string ( ) ,
612+ shard_placement_status : "active" . to_string ( ) ,
613+ database_role : "shard" . to_string ( ) ,
614+ database_status : "active" . to_string ( ) ,
615+ database_url_env : "VIGILO_SHARD_001_DATABASE_URL" . to_string ( ) ,
616+ database_url_env_resolved : true ,
617+ dispatchable : true ,
618+ readable : true ,
619+ routing_decision : "dispatchable" ,
620+ } ;
621+
622+ let payload = route_payload ( & route) ;
623+
624+ assert_eq ! ( payload[ "data" ] [ "run_id" ] , json!( run_id) ) ;
625+ assert_eq ! ( payload[ "data" ] [ "run_shard" ] , json!( 4 ) ) ;
626+ assert_eq ! ( payload[ "data" ] [ "database_alias" ] , json!( "shard_001" ) ) ;
627+ assert_eq ! (
628+ payload[ "data" ] [ "database_url_env" ] ,
629+ json!( "VIGILO_SHARD_001_DATABASE_URL" )
630+ ) ;
631+ assert ! (
632+ payload
633+ . to_string( )
634+ . contains( "VIGILO_SHARD_001_DATABASE_URL" )
635+ ) ;
636+ assert ! ( !payload. to_string( ) . contains( "postgres://" ) ) ;
637+ assert_eq ! ( payload[ "data" ] [ "routing_decision" ] , json!( "dispatchable" ) ) ;
638+ }
534639}
0 commit comments