@@ -2869,13 +2869,32 @@ def get_volume_names(compose, cnt):
2869
2869
2870
2870
@cmd_run (podman_compose , "down" , "tear down entire stack" )
2871
2871
async def compose_down (compose : PodmanCompose , args ):
2872
+ # get_excluded fails as no-deps is not a supported cli arg
2872
2873
excluded = get_excluded (compose , args )
2873
2874
podman_args = []
2874
2875
timeout_global = getattr (args , "timeout" , None )
2875
2876
containers = list (reversed (compose .containers ))
2876
2877
2877
- down_tasks = []
2878
+ # Get list of currently running containers
2879
+ running_cnt_names = (
2880
+ (
2881
+ await compose .podman .output (
2882
+ [],
2883
+ "ps" ,
2884
+ [
2885
+ "--filter" ,
2886
+ f"label=io.podman.compose.project={ compose .project_name } " ,
2887
+ "-a" ,
2888
+ "--format" ,
2889
+ "{{ .Names }}" ,
2890
+ ],
2891
+ )
2892
+ )
2893
+ .decode ("utf-8" )
2894
+ .splitlines ()
2895
+ )
2878
2896
2897
+ stop_tasks = []
2879
2898
for cnt in containers :
2880
2899
if cnt ["_service" ] in excluded :
2881
2900
continue
@@ -2886,38 +2905,58 @@ async def compose_down(compose: PodmanCompose, args):
2886
2905
timeout = str_to_seconds (timeout_str )
2887
2906
if timeout is not None :
2888
2907
podman_stop_args .extend (["-t" , str (timeout )])
2889
- down_tasks .append (
2890
- asyncio .create_task (
2891
- compose .podman .run ([], "stop" , [* podman_stop_args , cnt ["name" ]]), name = cnt ["name" ]
2892
- )
2893
- )
2894
- await asyncio .gather (* down_tasks )
2908
+ stop_tasks .append (compose .podman .run ([], "stop" , [* podman_stop_args , cnt ["name" ]]))
2909
+ await asyncio .gather (* stop_tasks )
2910
+ stop_tasks .clear ()
2911
+
2912
+ rm_tasks = []
2895
2913
for cnt in containers :
2896
2914
if cnt ["_service" ] in excluded :
2897
2915
continue
2898
- await compose .podman .run ([], "rm" , [cnt ["name" ]])
2916
+ rm_tasks .append (compose .podman .run ([], "rm" , [cnt ["name" ]]))
2917
+ if cnt ["name" ] in running_cnt_names :
2918
+ running_cnt_names .remove (cnt ["name" ])
2919
+ await asyncio .gather (* rm_tasks )
2920
+ rm_tasks .clear ()
2921
+
2922
+ # The logic is updated based on docker compose documentation:
2923
+ # `--remove-orphans`: Remove containers for services not defined in the Compose file
2924
+ # Ref: https://docs.docker.com/reference/cli/docker/compose/down/#options
2925
+ orphan_cnt_names = []
2926
+ for cnt in running_cnt_names :
2927
+ if not any (f"{ compose .project_name } _{ service } _" in cnt for service in compose .all_services ):
2928
+ orphan_cnt_names .append (cnt )
2929
+ running_cnt_names .remove (cnt )
2930
+
2931
+ # We list the containers and remove them from running container list
2932
+ # However, we stop them only if provided with CLI arg `--remove-orphans`
2899
2933
if args .remove_orphans :
2900
- names = (
2901
- (
2902
- await compose .podman .output (
2903
- [],
2904
- "ps" ,
2905
- [
2906
- "--filter" ,
2907
- f"label=io.podman.compose.project={ compose .project_name } " ,
2908
- "-a" ,
2909
- "--format" ,
2910
- "{{ .Names }}" ,
2911
- ],
2912
- )
2913
- )
2914
- .decode ("utf-8" )
2915
- .splitlines ()
2916
- )
2917
- for name in names :
2918
- await compose .podman .run ([], "stop" , [* podman_args , name ])
2919
- for name in names :
2920
- await compose .podman .run ([], "rm" , [name ])
2934
+ for name in orphan_cnt_names :
2935
+ stop_tasks .append (compose .podman .run ([], "stop" , [* podman_args , name ]))
2936
+ await asyncio .gather (* stop_tasks )
2937
+ stop_tasks .clear ()
2938
+
2939
+ for name in orphan_cnt_names :
2940
+ rm_tasks .append (compose .podman .run ([], "rm" , [name ]))
2941
+ await asyncio .gather (* rm_tasks )
2942
+ rm_tasks .clear ()
2943
+
2944
+ for cnt in running_cnt_names :
2945
+ # This logic goes away if the containers list can be updated accordingly at source
2946
+ # Clear containers not formed out of the current compose file definitions
2947
+ # E.g.: By using CLI `up --scale <APP>=<NUM>` option
2948
+ podman_stop_args = [* podman_args ]
2949
+ if timeout_global is not None :
2950
+ podman_stop_args .extend (["-t" , str (timeout_global )])
2951
+ stop_tasks .append (compose .podman .run ([], "stop" , [* podman_stop_args , cnt ]))
2952
+ await asyncio .gather (* stop_tasks )
2953
+ stop_tasks .clear ()
2954
+
2955
+ for cnt in running_cnt_names :
2956
+ rm_tasks .append (compose .podman .run ([], "rm" , [cnt ]))
2957
+ await asyncio .gather (* rm_tasks )
2958
+ rm_tasks .clear ()
2959
+
2921
2960
if args .volumes :
2922
2961
vol_names_to_keep = set ()
2923
2962
for cnt in containers :
0 commit comments