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
This commit is contained in:
Julien Duponchelle 2015-04-14 15:00:45 +02:00
parent 6ec081c774
commit e51a129216

View File

@ -41,6 +41,7 @@ class VirtualBox(BaseManager):
super().__init__() super().__init__()
self._vboxmanage_path = None self._vboxmanage_path = None
self._execute_lock = asyncio.Lock()
@property @property
def vboxmanage_path(self): def vboxmanage_path(self):
@ -82,34 +83,38 @@ class VirtualBox(BaseManager):
@asyncio.coroutine @asyncio.coroutine
def execute(self, subcommand, args, timeout=60): def execute(self, subcommand, args, timeout=60):
vboxmanage_path = self.vboxmanage_path # We use a lock prevent parallel execution due to strange errors
if not vboxmanage_path: # reported by a user and reproduced by us.
vboxmanage_path = self.find_vboxmanage() # https://github.com/GNS3/gns3-gui/issues/261
command = [vboxmanage_path, "--nologo", subcommand] with (yield from self._execute_lock):
command.extend(args) vboxmanage_path = self.vboxmanage_path
log.debug("Executing VBoxManage with command: {}".format(command)) if not vboxmanage_path:
try: vboxmanage_path = self.find_vboxmanage()
vbox_user = self.config.get_section_config("VirtualBox").get("vbox_user") command = [vboxmanage_path, "--nologo", subcommand]
if vbox_user: command.extend(args)
# TODO: test & review this part log.debug("Executing VBoxManage with command: {}".format(command))
sudo_command = "sudo -i -u {}".format(vbox_user) + " ".join(command) try:
process = yield from asyncio.create_subprocess_shell(sudo_command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) vbox_user = self.config.get_section_config("VirtualBox").get("vbox_user")
else: if vbox_user:
process = yield from asyncio.create_subprocess_exec(*command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) # TODO: test & review this part
except (OSError, subprocess.SubprocessError) as e: sudo_command = "sudo -i -u {}".format(vbox_user) + " ".join(command)
raise VirtualBoxError("Could not execute VBoxManage: {}".format(e)) 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: try:
stdout_data, stderr_data = yield from asyncio.wait_for(process.communicate(), timeout=timeout) stdout_data, stderr_data = yield from asyncio.wait_for(process.communicate(), timeout=timeout)
except asyncio.TimeoutError: except asyncio.TimeoutError:
raise VirtualBoxError("VBoxManage has timed out after {} seconds!".format(timeout)) raise VirtualBoxError("VBoxManage has timed out after {} seconds!".format(timeout))
if process.returncode: if process.returncode:
# only the first line of the output is useful # only the first line of the output is useful
vboxmanage_error = stderr_data.decode("utf-8", errors="ignore") vboxmanage_error = stderr_data.decode("utf-8", errors="ignore")
raise VirtualBoxError("VirtualBox has returned an error: {}".format(vboxmanage_error)) 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 @asyncio.coroutine
def get_list(self): def get_list(self):