From e51a129216e859fc96cf5b8c9fe48b2136db859e Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Tue, 14 Apr 2015 15:00:45 +0200 Subject: [PATCH] Prevent parallel execution of VBox commands In theory it should not be a problem. But It's create issues like this one: Fix: https://github.com/GNS3/gns3-gui/issues/261 --- gns3server/modules/virtualbox/__init__.py | 55 ++++++++++++----------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/gns3server/modules/virtualbox/__init__.py b/gns3server/modules/virtualbox/__init__.py index 5ea015e0..a6440072 100644 --- a/gns3server/modules/virtualbox/__init__.py +++ b/gns3server/modules/virtualbox/__init__.py @@ -41,6 +41,7 @@ class VirtualBox(BaseManager): super().__init__() self._vboxmanage_path = None + self._execute_lock = asyncio.Lock() @property def vboxmanage_path(self): @@ -82,34 +83,38 @@ class VirtualBox(BaseManager): @asyncio.coroutine def execute(self, subcommand, args, timeout=60): - vboxmanage_path = self.vboxmanage_path - if not vboxmanage_path: - vboxmanage_path = self.find_vboxmanage() - command = [vboxmanage_path, "--nologo", subcommand] - command.extend(args) - log.debug("Executing VBoxManage with command: {}".format(command)) - try: - vbox_user = self.config.get_section_config("VirtualBox").get("vbox_user") - if vbox_user: - # TODO: test & review this part - sudo_command = "sudo -i -u {}".format(vbox_user) + " ".join(command) - process = yield from asyncio.create_subprocess_shell(sudo_command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) - else: - process = yield from asyncio.create_subprocess_exec(*command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) - except (OSError, subprocess.SubprocessError) as e: - raise VirtualBoxError("Could not execute VBoxManage: {}".format(e)) + # We use a lock prevent parallel execution due to strange errors + # reported by a user and reproduced by us. + # https://github.com/GNS3/gns3-gui/issues/261 + with (yield from self._execute_lock): + vboxmanage_path = self.vboxmanage_path + if not vboxmanage_path: + vboxmanage_path = self.find_vboxmanage() + command = [vboxmanage_path, "--nologo", subcommand] + command.extend(args) + log.debug("Executing VBoxManage with command: {}".format(command)) + try: + vbox_user = self.config.get_section_config("VirtualBox").get("vbox_user") + if vbox_user: + # TODO: test & review this part + sudo_command = "sudo -i -u {}".format(vbox_user) + " ".join(command) + process = yield from asyncio.create_subprocess_shell(sudo_command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + else: + process = yield from asyncio.create_subprocess_exec(*command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + except (OSError, subprocess.SubprocessError) as e: + raise VirtualBoxError("Could not execute VBoxManage: {}".format(e)) - try: - stdout_data, stderr_data = yield from asyncio.wait_for(process.communicate(), timeout=timeout) - except asyncio.TimeoutError: - raise VirtualBoxError("VBoxManage has timed out after {} seconds!".format(timeout)) + try: + stdout_data, stderr_data = yield from asyncio.wait_for(process.communicate(), timeout=timeout) + except asyncio.TimeoutError: + raise VirtualBoxError("VBoxManage has timed out after {} seconds!".format(timeout)) - if process.returncode: - # only the first line of the output is useful - vboxmanage_error = stderr_data.decode("utf-8", errors="ignore") - raise VirtualBoxError("VirtualBox has returned an error: {}".format(vboxmanage_error)) + if process.returncode: + # only the first line of the output is useful + vboxmanage_error = stderr_data.decode("utf-8", errors="ignore") + raise VirtualBoxError("VirtualBox has returned an error: {}".format(vboxmanage_error)) - return stdout_data.decode("utf-8", errors="ignore").splitlines() + return stdout_data.decode("utf-8", errors="ignore").splitlines() @asyncio.coroutine def get_list(self):