Skip to content

Commit 828362d

Browse files
committed
Implement parameter to control removal policy of exited containers
1 parent 8a6810c commit 828362d

1 file changed

Lines changed: 32 additions & 1 deletion

File tree

src/multicosim/containers.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import abc
2424
import asyncio
25+
import contextlib
2526
import errno
2627
import logging
2728
import os
@@ -52,6 +53,7 @@
5253
from .simulations import Simulator as _Simulator
5354

5455
Container: typing_extensions.TypeAlias = docker.models.containers.Container
56+
Remove = typing.Literal["always", "if_exit_success", "never"]
5557

5658

5759
@attrs.define()
@@ -427,10 +429,25 @@ async def send(self, component: ConnectedComponent[MsgT, DataT], msg: MsgT) -> D
427429
return retval.data
428430

429431
@typing_extensions.override
430-
def stop(self) -> None:
432+
def stop(self, *, remove: Remove = "if_exit_success"):
431433
for child in self.children.values():
432434
child.container.stop()
433435

436+
match remove:
437+
case "always":
438+
child.container.remove()
439+
case "never":
440+
pass
441+
case _:
442+
status = child.container.wait()
443+
444+
# 0 -> ExitSucess, 137 -> SIGKILL, 143 -> SIGTERM
445+
if status["StatusCode"] in {0, 137, 143}:
446+
child.container.remove()
447+
448+
if remove is not "never":
449+
self.context.network.remove()
450+
434451

435452
@attrs.define()
436453
class _Registration:
@@ -445,6 +462,9 @@ def start(self, context: Context) -> _ComponentSimulation:
445462
return _ComponentSimulation(self.component.start(context), self.dependencies)
446463

447464

465+
_SimulationGenerator: typing.TypeAlias = typing.Generator[Simulation, None, None]
466+
467+
448468
class Simulator(_Simulator[Context, Simulation]):
449469
"""Simulator implementation using container-based components."""
450470

@@ -499,6 +519,17 @@ def start(self) -> Simulation:
499519

500520
raise e
501521

522+
@contextlib.contextmanager
523+
@typing_extensions.override
524+
def run(self, *, remove: Remove = "if_exit_success") -> _SimulationGenerator:
525+
sim = self.start()
526+
527+
try:
528+
yield sim
529+
finally:
530+
sim.stop(remove=remove)
531+
532+
502533

503534
@attrs.frozen()
504535
class Success(typing.Generic[DataT]):

0 commit comments

Comments
 (0)