mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-09-16 06:50:41 +03:00
fix: run the reclaim helper as root regardless of the image's default USER
The one-shot reclaim container inherited the image's baked-in USER: ghcr.io/nokia/srlinux runs as "user:user", so the "privileged" helper was exactly as unprivileged as the server itself — chmod/chown on files written by other uids (srlinux writes as a large internal uid) failed with EPERM and node/project deletion still broke, just with a different error. Pass --user 0:0 explicitly so the helper is root no matter what the image declares, and fix the manual reclaim hint the same way. Validated live on two stuck srlinux node directories (257/258 foreign-owned entries reclaimed to 0 in ~0.5 s each).
This commit is contained in:
parent
54d9d7c08f
commit
4b239cc11a
@ -1092,10 +1092,14 @@ class DockerVM(BaseNode):
|
||||
# as the container-side pass in _fix_permissions). --pull=never keeps
|
||||
# a stale tag reference from turning into a registry pull attempt,
|
||||
# and the create-time image ID (when known) is immune to retagging.
|
||||
# --user 0:0 overrides a USER baked into the image (e.g.
|
||||
# ghcr.io/nokia/srlinux runs as "user"): without it the "privileged"
|
||||
# helper is exactly as unprivileged as the server itself and
|
||||
# chmod/chown fail with EPERM on files written by other uids.
|
||||
image_ref = self._image_id or self._image
|
||||
try:
|
||||
process = await asyncio.subprocess.create_subprocess_exec(
|
||||
"docker", "run", "--rm", "--network", "none", "--pull", "never",
|
||||
"docker", "run", "--rm", "--network", "none", "--pull", "never", "--user", "0:0",
|
||||
"--entrypoint", "/gns3/bin/busybox",
|
||||
"-v", f"{resources_path}:/gns3:ro",
|
||||
"-v", f"{directory}:/target",
|
||||
@ -2049,7 +2053,7 @@ class DockerVM(BaseNode):
|
||||
pass
|
||||
raise ComputeError(
|
||||
f"Could not delete the node directory '{self.working_dir}': files left owned by "
|
||||
f"root could not be reclaimed ({e}). Reclaim them manually with: "
|
||||
f"docker run --rm -v \"{self.working_dir}\":/target --entrypoint /bin/sh "
|
||||
f"another user could not be reclaimed ({e}). Reclaim them manually with: "
|
||||
f"docker run --rm --user 0:0 -v \"{self.working_dir}\":/target --entrypoint /bin/sh "
|
||||
f"{self._image} -c 'chown -R {os.getuid()}:{os.getgid()} /target'"
|
||||
)
|
||||
|
||||
@ -2093,7 +2093,7 @@ async def test_reclaim_runs_helper_container(vm, tmp_path):
|
||||
assert await vm._reclaim_directory_ownership(str(directory)) is True
|
||||
|
||||
args, _ = mock_exec.call_args
|
||||
assert args[:7] == ("docker", "run", "--rm", "--network", "none", "--pull", "never")
|
||||
assert args[:9] == ("docker", "run", "--rm", "--network", "none", "--pull", "never", "--user", "0:0")
|
||||
assert args[args.index("--entrypoint") + 1] == "/gns3/bin/busybox"
|
||||
assert "/gns3-share:/gns3:ro" in args
|
||||
assert f"{directory}:/target" in args
|
||||
@ -2149,7 +2149,7 @@ async def test_delete_reports_root_files_when_reclaim_fails(vm):
|
||||
with patch.object(vm, "_reclaim_directory_ownership", new_callable=AsyncioMagicMock, return_value=False):
|
||||
with patch("gns3server.compute.base_node.shutil.rmtree",
|
||||
side_effect=OSError("permission denied")):
|
||||
with pytest.raises(ComputeError, match="owned by root"):
|
||||
with pytest.raises(ComputeError, match="owned by another user"):
|
||||
await vm.delete()
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user