mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-04 14:31:13 +02:00
docker: graceful stop for vendor NOS containers (SIGTERM + 60s grace)
DockerVM.stop() terminated containers with an immediate SIGKILL — fine
for init.sh-based containers whose state is persisted beforehand, but a
systemd NOS (Cisco XRd, SR Linux) needs a graceful shutdown and treats
the abrupt kill as an unclean shutdown (exit 137 on every stop).
Extract the final termination into _terminate_container() and override
it in VendorDockerVM: POST /containers/{id}/stop?t=60 sends SIGTERM and
waits for systemd to stop services; Docker itself SIGKILLs the
container once the grace period expires, so no fallback is needed.
Docker's 304 (already stopped) is swallowed.
This commit is contained in:
4 files changed
+103
-16
No files matched your search
@@ -35,7 +35,7 @@ import shutil
|
||||
|
||||
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
|
||||
from gns3server.compute.docker.docker_vm import DockerVM
|
||||
from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Error
|
||||
from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -138,6 +138,20 @@ class VendorDockerVM(DockerVM):
|
||||
pass
|
||||
self._console_exec_writer = None
|
||||
|
||||
async def _terminate_container(self):
|
||||
"""
|
||||
Override: vendor NOS containers run systemd and require a graceful
|
||||
shutdown (e.g. Cisco XRd treats an abrupt SIGKILL as an unclean
|
||||
shutdown). Send SIGTERM and wait up to 60 s for the services to stop;
|
||||
Docker SIGKILLs the container itself once the grace period expires,
|
||||
so no fallback kill is needed. The blocking stop call sits well
|
||||
inside the manager's default 300 s query timeout.
|
||||
"""
|
||||
try:
|
||||
await self.manager.query("POST", f"containers/{self._cid}/stop", params={"t": 60})
|
||||
except DockerHttp304Error:
|
||||
pass # already stopped
|
||||
|
||||
async def start(self):
|
||||
await super().start()
|
||||
if self.status == "started" and not self._gns3_init:
|
||||
|
||||
Reference in new issue
Block a user