Fix bug and add optimizations when connecting and sending commands to QEMU monitor after starting a VM. Fixes #2336.

This commit is contained in:
grossmj 2018-03-23 00:07:32 +07:00
parent 135bbe8825
commit a40fdb3641
2 changed files with 63 additions and 9 deletions

View File

@ -90,7 +90,7 @@ class DynamipsHypervisor:
if not connection_success:
raise DynamipsError("Couldn't connect to hypervisor on {}:{} :{}".format(host, self._port, last_exception))
else:
log.info("Connected to Dynamips hypervisor after {:.4f} seconds".format(time.time() - begin))
log.info("Connected to Dynamips hypervisor on {}:{} after {:.4f} seconds".format(host, self._port, time.time() - begin))
try:
version = yield from self.send("hypervisor version")

View File

@ -30,6 +30,7 @@ import asyncio
import socket
import gns3server
import subprocess
import time
from gns3server.utils import parse_version
from gns3server.utils.asyncio import subprocess_check_output, cancellable_wait_run_in_executor
@ -956,6 +957,7 @@ class QemuVM(BaseNode):
self._hw_virtualization = True
yield from self._start_ubridge()
set_link_commands = []
for adapter_number, adapter in enumerate(self._ethernet_adapters):
nio = adapter.get_nio(0)
if nio:
@ -963,9 +965,10 @@ class QemuVM(BaseNode):
self._local_udp_tunnels[adapter_number][1],
nio)
if nio.suspend:
yield from self._control_vm("set_link gns3-{} off".format(adapter_number))
set_link_commands.append("set_link gns3-{} off".format(adapter_number))
else:
yield from self._control_vm("set_link gns3-{} off".format(adapter_number))
set_link_commands.append("set_link gns3-{} off".format(adapter_number))
yield from self._control_vm_commands(set_link_commands)
try:
yield from self.start_wrap_console()
@ -1020,6 +1023,37 @@ class QemuVM(BaseNode):
self._stop_cpulimit()
yield from super().stop()
@asyncio.coroutine
def _open_qemu_monitor_connection_vm(self, timeout=10):
"""
Opens a connection to the QEMU monitor.
:param timeout: timeout to connect to the monitor TCP server
:returns: The reader returned is a StreamReader instance; the writer is a StreamWriter instance
"""
begin = time.time()
connection_success = False
last_exception = None
reader = writer = None
while time.time() - begin < timeout:
yield from asyncio.sleep(0.01)
try:
log.debug("Connecting to Qemu monitor on {}:{}".format(self._monitor_host, self._monitor))
reader, writer = yield from asyncio.open_connection(self._monitor_host, self._monitor)
except (asyncio.TimeoutError, OSError) as e:
last_exception = e
continue
connection_success = True
break
if not connection_success:
log.warning("Could not connect to QEMU monitor on {}:{}: {}".format(self._monitor_host, self._monitor,
last_exception))
else:
log.info("Connected to QEMU monitor on {}:{} after {:.4f} seconds".format(self._monitor_host, self._monitor, time.time() - begin))
return reader, writer
@asyncio.coroutine
def _control_vm(self, command, expected=None):
"""
@ -1033,13 +1067,11 @@ class QemuVM(BaseNode):
result = None
if self.is_running() and self._monitor:
log.debug("Execute QEMU monitor command: {}".format(command))
try:
log.debug("Connecting to Qemu monitor on {}:{}".format(self._monitor_host, self._monitor))
reader, writer = yield from asyncio.open_connection(self._monitor_host, self._monitor)
except OSError as e:
log.warning("Could not connect to QEMU monitor on {}:{}: {}".format(self._monitor_host, self._monitor, e))
log.info("Execute QEMU monitor command: {}".format(command))
reader, writer = yield from self._open_qemu_monitor_connection_vm()
if reader is None and writer is None:
return result
try:
writer.write(command.encode('ascii') + b"\n")
except OSError as e:
@ -1061,6 +1093,28 @@ class QemuVM(BaseNode):
writer.close()
return result
@asyncio.coroutine
def _control_vm_commands(self, commands):
"""
Executes commands with QEMU monitor when this VM is running.
:param commands: a list of QEMU monitor commands (e.g. info status, stop etc.)
"""
if self.is_running() and self._monitor:
reader, writer = yield from self._open_qemu_monitor_connection_vm()
if reader is None and writer is None:
return
for command in commands:
log.info("Execute QEMU monitor command: {}".format(command))
try:
writer.write(command.encode('ascii') + b"\n")
except OSError as e:
log.warning("Could not write to QEMU monitor: {}".format(e))
writer.close()
@asyncio.coroutine
def close(self):
"""