mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
docker: don't recreate containers on empty-string property PUTs
Web clients serialize empty form fields as "" while unset values are
stored as None on the node. The bare != diff in the update handler then
sees a phantom change on every full PUT and recreates the container for
nothing -- even when the user only changed a controller-only field such
as netmiko_device_type.
Normalize at the schema boundary ("" -> None for start_command,
environment and extra_hosts; "" -> "/" for console_http_path), make
the setters apply the same canonicalization, and create nodes through
the setters instead of bypassing them in __init__ so both paths store
identical values.
This commit is contained in:
3 files changed
+68
-8
No files matched your search
@@ -306,6 +306,45 @@ class TestDockerNodesRoutes:
|
||||
assert response.json()["environment"] == "GNS3=1\nGNS4=0"
|
||||
assert response.json()["extra_hosts"] == "test:127.0.0.1"
|
||||
|
||||
async def test_docker_update_empty_strings_do_not_recreate_container(
|
||||
self,
|
||||
app: FastAPI,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project
|
||||
) -> None:
|
||||
"""
|
||||
Web clients serialize empty form fields as "" while unset values are
|
||||
stored as None on the node: a full PUT must not see a phantom change
|
||||
and recreate the container for nothing.
|
||||
"""
|
||||
|
||||
params = {"name": "DOCKER-EMPTY", "image": "nginx", "environment": ""}
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
|
||||
response = await compute_client.post(
|
||||
app.url_path_for("compute:create_docker_node", project_id=compute_project.id), json=params
|
||||
)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["environment"] is None # "" normalized at creation
|
||||
assert response.json()["console_http_path"] == "/"
|
||||
node_id = response.json()["node_id"]
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.update") as mock:
|
||||
response = await compute_client.put(
|
||||
app.url_path_for("compute:update_docker_node", project_id=compute_project.id, node_id=node_id),
|
||||
json={
|
||||
"name": "DOCKER-EMPTY",
|
||||
"start_command": "",
|
||||
"environment": "",
|
||||
"extra_hosts": "",
|
||||
"console_http_path": "",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert not mock.called # no real change: the container must not be recreated
|
||||
assert response.json()["start_command"] is None
|
||||
assert response.json()["console_http_path"] == "/"
|
||||
|
||||
|
||||
async def test_docker_start_capture(self, app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
|
||||
Reference in new issue
Block a user