@@ -140,7 +140,7 @@ def container_exists(self, name: str, max_retries: int = 3):
140140 """
141141 for attempt in range (max_retries ):
142142 try :
143- self .execute (f""" docker ps --all --filter "name=^ { name } $" | grep { name } "" " )
143+ self .execute (f"docker inspect { name } " )
144144 except AgentException :
145145 break # container does not exist
146146 else :
@@ -201,6 +201,21 @@ def get_reclaimable_size(self) -> dict[str, dict[str, float] | float]:
201201 "total" : round ((unused_images_size + total_archived_folder_size ) / 1024 ** 3 , 2 ),
202202 }
203203
204+ @job ("Force Remove Zombie Benches" )
205+ def force_remove_zombie_benches (self , bench_names : list [str ]):
206+ return self ._force_remove_zombie_benches (bench_names )
207+
208+ @step ("Force Remove Zombie Benches" )
209+ def _force_remove_zombie_benches (self , bench_names : list [str ]):
210+ for bench_name in bench_names :
211+ try :
212+ self .execute (f"""docker ps --all --filter "name=^{ bench_name } $" | grep { bench_name } """ )
213+ except AgentException :
214+ continue # Bench is gone
215+
216+ self .disable_production_on_bench (bench_name )
217+ self ._move_bench_to_archived_directory (bench_name )
218+
204219 @job ("Push Images to Registry" )
205220 def push_images_to_registry (self , images : list [str ], registry_settings : dict [str , str ]) -> None :
206221 return self ._push_images_to_registry (images , registry_settings )
@@ -456,8 +471,7 @@ def remove_unused_docker_artefacts(self):
456471 "after" : after ,
457472 }
458473
459- @step ("Move Bench to Archived Directory" )
460- def move_bench_to_archived_directory (self , bench_name ):
474+ def _move_bench_to_archived_directory (self , bench_name ):
461475 if not os .path .exists (self .archived_directory ):
462476 os .mkdir (self .archived_directory )
463477 target = os .path .join (self .archived_directory , bench_name )
@@ -472,6 +486,10 @@ def move_bench_to_archived_directory(self, bench_name):
472486
473487 self .execute (f"mv { bench_directory } { self .archived_directory } " )
474488
489+ @step ("Move Bench to Archived Directory" )
490+ def move_bench_to_archived_directory (self , bench_name ):
491+ self ._move_bench_to_archived_directory (bench_name )
492+
475493 @job ("Update Site Pull" , priority = "low" )
476494 def update_site_pull_job (self , name , source , target , activate ):
477495 source = Bench (source , self )
@@ -803,6 +821,10 @@ def get_bench(self, bench):
803821 except KeyError as exc :
804822 raise BenchNotExistsException (bench ) from exc
805823
824+ def get_running_bench_containers (self ) -> list [str ]:
825+ """Get the actual containers skipping the `Server.benches` property"""
826+ return self .execute ("docker ps --format '{{.Names}}'" )["output" ].split ("\n " )
827+
806828 @property
807829 def job_record (self ):
808830 if self .job is None :
0 commit comments