mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 14:01:15 +02:00
feat: sync Docker images from the controller to remote computes
When a Docker node is created on a remote compute whose Docker daemon does not have the image, the compute now raises ImageMissingError instead of blindly pulling from the Docker repository. The controller exports the image from the Docker daemon on its host (docker save stream) and streams it to the compute which loads it, so locally built or docker-loaded images work across computes. When the image is not available on the controller host either, the compute is asked to pull it from the Docker repository as a fallback. - add a POST /docker/images/load compute endpoint that streams a docker save tar into the Docker daemon - let Docker.http_query pass raw (non-dict) request bodies through so the tar can be streamed to the daemon - drop the inline pull from DockerVM.create() and the now unused DockerVM.pull_image wrapper
This commit is contained in:
8 files changed
+215
-75
No files matched your search
@@ -770,6 +770,9 @@ class Node:
|
||||
if the image exists
|
||||
"""
|
||||
|
||||
if self._node_type == "docker":
|
||||
return await self._sync_missing_docker_image(img)
|
||||
|
||||
for directory in images_directories(type):
|
||||
image = os.path.join(directory, img)
|
||||
if os.path.exists(image):
|
||||
@@ -785,6 +788,43 @@ class Node:
|
||||
return True
|
||||
return False
|
||||
|
||||
async def _sync_missing_docker_image(self, image):
|
||||
"""
|
||||
Export a Docker image from the Docker daemon on the controller host and
|
||||
stream it to the remote compute, or ask the compute to pull it when the
|
||||
image is not available locally
|
||||
"""
|
||||
|
||||
from gns3server.compute.docker import Docker
|
||||
from gns3server.compute.docker.docker_error import DockerError
|
||||
|
||||
try:
|
||||
response = await Docker.instance().http_query("GET", f"images/{image}/get", timeout=None)
|
||||
except DockerError:
|
||||
# the image is not on the Docker daemon of the controller host: ask the
|
||||
# compute to pull it from the Docker repository as a fallback
|
||||
self.project.emit_notification(
|
||||
"log.info",
|
||||
{"message": f"Docker image '{image}' is not on the controller host, "
|
||||
f"asking compute '{self._compute.name}' to pull it"}
|
||||
)
|
||||
await self._compute.post("/docker/images/pull", data={"image": image}, timeout=None)
|
||||
return True
|
||||
|
||||
self.project.emit_notification(
|
||||
"log.info",
|
||||
{"message": f"Syncing Docker image '{image}' to compute '{self._compute.name}'"}
|
||||
)
|
||||
try:
|
||||
await self._compute.post("/docker/images/load", data=response.content, timeout=None)
|
||||
finally:
|
||||
response.close()
|
||||
self.project.emit_notification(
|
||||
"log.info",
|
||||
{"message": f"Docker image '{image}' has been synced to compute '{self._compute.name}'"}
|
||||
)
|
||||
return True
|
||||
|
||||
async def dynamips_auto_idlepc(self):
|
||||
"""
|
||||
Compute the idle PC for a dynamips node
|
||||
|
||||
Reference in new issue
Block a user