1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-28 11:18:11 +00:00

Lock qemu vm during start / stop operations

Fix #301
This commit is contained in:
Julien Duponchelle 2015-08-27 16:06:11 +02:00
parent 699647dbda
commit c361d27531
2 changed files with 65 additions and 60 deletions

View File

@ -71,6 +71,7 @@ class QemuVM(BaseVM):
self._cpulimit_process = None self._cpulimit_process = None
self._monitor = None self._monitor = None
self._stdout_file = "" self._stdout_file = ""
self._execute_lock = asyncio.Lock()
# QEMU VM settings # QEMU VM settings
if qemu_path: if qemu_path:
@ -818,54 +819,55 @@ class QemuVM(BaseVM):
Starts this QEMU VM. Starts this QEMU VM.
""" """
if self.is_running(): with (yield from self._execute_lock):
# resume the VM if it is paused if self.is_running():
yield from self.resume() # resume the VM if it is paused
return yield from self.resume()
return
else: else:
if self._manager.config.get_section_config("Qemu").getboolean("monitor", True): if self._manager.config.get_section_config("Qemu").getboolean("monitor", True):
try:
info = socket.getaddrinfo(self._monitor_host, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
if not info:
raise QemuError("getaddrinfo returns an empty list on {}".format(self._monitor_host))
for res in info:
af, socktype, proto, _, sa = res
# let the OS find an unused port for the Qemu monitor
with socket.socket(af, socktype, proto) as sock:
sock.bind(sa)
self._monitor = sock.getsockname()[1]
except OSError as e:
raise QemuError("Could not find free port for the Qemu monitor: {}".format(e))
self._command = yield from self._build_command()
command_string = " ".join(shlex.quote(s) for s in self._command)
try: try:
info = socket.getaddrinfo(self._monitor_host, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) log.info("Starting QEMU with: {}".format(command_string))
if not info: self._stdout_file = os.path.join(self.working_dir, "qemu.log")
raise QemuError("getaddrinfo returns an empty list on {}".format(self._monitor_host)) log.info("logging to {}".format(self._stdout_file))
for res in info: with open(self._stdout_file, "w", encoding="utf-8") as fd:
af, socktype, proto, _, sa = res fd.write("Start QEMU with {}\n\nExecution log:\n".format(command_string))
# let the OS find an unused port for the Qemu monitor self._process = yield from asyncio.create_subprocess_exec(*self._command,
with socket.socket(af, socktype, proto) as sock: stdout=fd,
sock.bind(sa) stderr=subprocess.STDOUT,
self._monitor = sock.getsockname()[1] cwd=self.working_dir)
except OSError as e: log.info('QEMU VM "{}" started PID={}'.format(self._name, self._process.pid))
raise QemuError("Could not find free port for the Qemu monitor: {}".format(e))
self._command = yield from self._build_command() self.status = "started"
command_string = " ".join(shlex.quote(s) for s in self._command) monitor_process(self._process, self._termination_callback)
try: except (OSError, subprocess.SubprocessError, UnicodeEncodeError) as e:
log.info("Starting QEMU with: {}".format(command_string)) stdout = self.read_stdout()
self._stdout_file = os.path.join(self.working_dir, "qemu.log") log.error("Could not start QEMU {}: {}\n{}".format(self.qemu_path, e, stdout))
log.info("logging to {}".format(self._stdout_file)) raise QemuError("Could not start QEMU {}: {}\n{}".format(self.qemu_path, e, stdout))
with open(self._stdout_file, "w", encoding="utf-8") as fd:
fd.write("Start QEMU with {}\n\nExecution log:\n".format(command_string))
self._process = yield from asyncio.create_subprocess_exec(*self._command,
stdout=fd,
stderr=subprocess.STDOUT,
cwd=self.working_dir)
log.info('QEMU VM "{}" started PID={}'.format(self._name, self._process.pid))
self.status = "started" self._set_process_priority()
monitor_process(self._process, self._termination_callback) if self._cpu_throttling:
except (OSError, subprocess.SubprocessError, UnicodeEncodeError) as e: self._set_cpu_throttling()
stdout = self.read_stdout()
log.error("Could not start QEMU {}: {}\n{}".format(self.qemu_path, e, stdout))
raise QemuError("Could not start QEMU {}: {}\n{}".format(self.qemu_path, e, stdout))
self._set_process_priority() if "-enable-kvm" in command_string:
if self._cpu_throttling: self._hw_virtualization = True
self._set_cpu_throttling()
if "-enable-kvm" in command_string:
self._hw_virtualization = True
def _termination_callback(self, returncode): def _termination_callback(self, returncode):
""" """
@ -888,24 +890,25 @@ class QemuVM(BaseVM):
Stops this QEMU VM. Stops this QEMU VM.
""" """
# stop the QEMU process with (yield from self._execute_lock):
self._hw_virtualization = False # stop the QEMU process
if self.is_running(): self._hw_virtualization = False
log.info('Stopping QEMU VM "{}" PID={}'.format(self._name, self._process.pid)) if self.is_running():
self.status = "stopped" log.info('Stopping QEMU VM "{}" PID={}'.format(self._name, self._process.pid))
try: self.status = "stopped"
if self.acpi_shutdown: try:
yield from self._control_vm("system_powerdown") if self.acpi_shutdown:
yield from gns3server.utils.asyncio.wait_for_process_termination(self._process, timeout=30) yield from self._control_vm("system_powerdown")
else: yield from gns3server.utils.asyncio.wait_for_process_termination(self._process, timeout=30)
self._process.terminate() else:
yield from gns3server.utils.asyncio.wait_for_process_termination(self._process, timeout=3) self._process.terminate()
except asyncio.TimeoutError: yield from gns3server.utils.asyncio.wait_for_process_termination(self._process, timeout=3)
self._process.kill() except asyncio.TimeoutError:
if self._process.returncode is None: self._process.kill()
log.warn('QEMU VM "{}" PID={} is still running'.format(self._name, self._process.pid)) if self._process.returncode is None:
self._process = None log.warn('QEMU VM "{}" PID={} is still running'.format(self._name, self._process.pid))
self._stop_cpulimit() self._process = None
self._stop_cpulimit()
@asyncio.coroutine @asyncio.coroutine
def _control_vm(self, command, expected=None): def _control_vm(self, command, expected=None):

View File

@ -104,6 +104,8 @@ class Route(object):
if request.headers["AUTHORIZATION"] == aiohttp.helpers.BasicAuth(user, password).encode(): if request.headers["AUTHORIZATION"] == aiohttp.helpers.BasicAuth(user, password).encode():
return return
log.error("Invalid auth. Username should %s", user)
response = Response(request=request, route=route) response = Response(request=request, route=route)
response.set_status(401) response.set_status(401)
response.headers["WWW-Authenticate"] = 'Basic realm="GNS3 server"' response.headers["WWW-Authenticate"] = 'Basic realm="GNS3 server"'