Merge pull request #1147 from GNS3/fix_docker_permission

Fix permission on exited container
This commit is contained in:
Jeremy Grossmann 2017-08-01 00:30:56 +08:00 committed by GitHub
commit 8a028a6dce
2 changed files with 40 additions and 10 deletions

View File

@ -416,16 +416,30 @@ class DockerVM(BaseNode):
Because docker run as root we need to fix permission and ownership to allow user to interact Because docker run as root we need to fix permission and ownership to allow user to interact
with it from their filesystem and do operation like file delete with it from their filesystem and do operation like file delete
""" """
state = yield from self._get_container_state()
if state == "stopped" or state == "exited":
# We need to restart it to fix permissions
yield from self.manager.query("POST", "containers/{}/start".format(self._cid))
for volume in self._volumes: for volume in self._volumes:
log.debug("Docker container '{name}' [{image}] fix ownership on {path}".format( log.debug("Docker container '{name}' [{image}] fix ownership on {path}".format(
name=self._name, image=self._image, path=volume)) name=self._name, image=self._image, path=volume))
process = yield from asyncio.subprocess.create_subprocess_exec("docker", process = yield from asyncio.subprocess.create_subprocess_exec(
"docker",
"exec", "exec",
self._cid, self._cid,
"/gns3/bin/busybox", "/gns3/bin/busybox",
"sh", "sh",
"-c", "-c",
"(/gns3/bin/busybox find \"{path}\" -depth -print0 | /gns3/bin/busybox xargs -0 /gns3/bin/busybox stat -c '%a:%u:%g:%n' > \"{path}/.gns3_perms\") && /gns3/bin/busybox chmod -R u+rX \"{path}\" && /gns3/bin/busybox chown {uid}:{gid} -R \"{path}\"".format(uid=os.getuid(), gid=os.getgid(), path=volume)) "("
"/gns3/bin/busybox find \"{path}\" -depth -print0"
" | /gns3/bin/busybox xargs -0 /gns3/bin/busybox stat -c '%a:%u:%g:%n' > \"{path}/.gns3_perms\""
")"
" && /gns3/bin/busybox chmod -R u+rX \"{path}\""
" && /gns3/bin/busybox chown {uid}:{gid} -R \"{path}\""
.format(uid=os.getuid(), gid=os.getgid(), path=volume),
)
yield from process.wait() yield from process.wait()
@asyncio.coroutine @asyncio.coroutine
@ -564,13 +578,15 @@ class DockerVM(BaseNode):
try: try:
state = yield from self._get_container_state() state = yield from self._get_container_state()
except DockerHttp404Error: except DockerHttp404Error:
state = "stopped" self.status = "stopped"
return
if state == "paused": if state == "paused":
yield from self.unpause() yield from self.unpause()
if state != "stopped":
yield from self._fix_permissions() yield from self._fix_permissions()
state = yield from self._get_container_state()
if state != "stopped" or state != "exited":
# t=5 number of seconds to wait before killing the container # t=5 number of seconds to wait before killing the container
try: try:
yield from self.manager.query("POST", "containers/{}/stop".format(self._cid), params={"t": 5}) yield from self.manager.query("POST", "containers/{}/stop".format(self._cid), params={"t": 5})

View File

@ -934,6 +934,7 @@ def test_create_network_interfaces(vm):
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows") @pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_fix_permission(vm, loop): def test_fix_permission(vm, loop):
vm._volumes = ["/etc"] vm._volumes = ["/etc"]
vm._get_container_state = AsyncioMagicMock(return_value="running")
process = MagicMock() process = MagicMock()
with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=process) as mock_exec: with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=process) as mock_exec:
loop.run_until_complete(vm._fix_permissions()) loop.run_until_complete(vm._fix_permissions())
@ -941,6 +942,19 @@ def test_fix_permission(vm, loop):
assert process.wait.called assert process.wait.called
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_fix_permission_not_running(vm, loop):
vm._volumes = ["/etc"]
vm._get_container_state = AsyncioMagicMock(return_value="stopped")
process = MagicMock()
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_start:
with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=process) as mock_exec:
loop.run_until_complete(vm._fix_permissions())
mock_exec.assert_called_with('docker', 'exec', 'e90e34656842', '/gns3/bin/busybox', 'sh', '-c', '(/gns3/bin/busybox find "/etc" -depth -print0 | /gns3/bin/busybox xargs -0 /gns3/bin/busybox stat -c \'%a:%u:%g:%n\' > "/etc/.gns3_perms") && /gns3/bin/busybox chmod -R u+rX "/etc" && /gns3/bin/busybox chown {}:{} -R "/etc"'.format(os.getuid(), os.getgid()))
assert mock_start.called
assert process.wait.called
def test_read_console_output_with_binary_mode(vm, loop): def test_read_console_output_with_binary_mode(vm, loop):
class InputStreamMock(object): class InputStreamMock(object):
def __init__(self): def __init__(self):