-
Notifications
You must be signed in to change notification settings - Fork 242
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Monitor: Support monitor on the multi-host
Signed-off-by: Yongxue Hong <yhong@redhat.com>
- Loading branch information
1 parent
e69c15e
commit 9e59b2e
Showing
13 changed files
with
1,822 additions
and
170 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import logging | ||
import os | ||
|
||
from vt_agent.core.data_dir import LOG_DIR | ||
|
||
from virttest.vt_monitor import client | ||
|
||
LOG = logging.getLogger("avocado.service." + __name__) | ||
|
||
|
||
def create_connect_client(instance_id, name, protocol, client_params, log_file=None): | ||
backend = client_params.get("backend") | ||
|
||
if log_file is None: | ||
log_file = "%s-instance-%s.log" % (name, instance_id) | ||
log_file = os.path.join(LOG_DIR, log_file) | ||
|
||
if backend == "socket": | ||
host = client_params.get("host") | ||
port = client_params.get("port") | ||
path = client_params.get("path") | ||
if host and port: | ||
address = (host, port) | ||
backend_type = "tcp_socket" | ||
elif path: | ||
address = path | ||
backend_type = "unix_socket" | ||
else: | ||
raise ValueError("No address specified for connect client") | ||
else: | ||
raise NotImplementedError("Not support connect backend type %s" % backend) | ||
|
||
if protocol == "qmp": | ||
return client.QMPMonitor(instance_id, name, backend_type, address, log_file) | ||
elif protocol == "hmp": | ||
return client.HumanMonitor(instance_id, name, backend_type, address, log_file) | ||
else: | ||
raise NotImplementedError("Unsupported connect protocol %s" % protocol) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import logging | ||
|
||
from .connect import ConnectManager | ||
from .console import ConsoleManager | ||
|
||
connect_mgr = ConnectManager() | ||
console_mgr = ConsoleManager() | ||
|
||
LOG = logging.getLogger("avocado.service." + __name__) | ||
|
||
# workaround to skip the failure of the import managers | ||
try: | ||
from .image import ImageHandlerManager | ||
from .resource_backing import ResourceBackingManager | ||
|
||
resbacking_mgr = ResourceBackingManager() | ||
image_handler_mgr = ImageHandlerManager() | ||
except ImportError as e: | ||
LOG.warning(f"Failed to import managers: {e}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import logging | ||
|
||
from vt_agent.connect_client import qemu | ||
|
||
LOG = logging.getLogger("avocado.service." + __name__) | ||
|
||
|
||
class ConnectManager(object): | ||
""" | ||
Manager the connection to the monitor | ||
""" | ||
|
||
def __init__(self): | ||
self._connects = {} | ||
|
||
@staticmethod | ||
def create_connect( | ||
instance_id, instance_type, name, protocol, params, log_file=None | ||
): | ||
LOG.info(f"<Instance: {instance_id}> Create a {protocol} connection {name}") | ||
if instance_type == "qemu": | ||
connect = qemu.create_connect_client( | ||
instance_id, name, protocol, params, log_file=log_file | ||
) | ||
return connect | ||
elif instance_type == "libvirt": | ||
raise NotImplementedError("Not implemented") | ||
else: | ||
raise NotImplementedError(f"Unsupported connect type {instance_type}") | ||
|
||
def register_connect(self, con_id, connect): | ||
if con_id in self._connects: | ||
raise ValueError | ||
self._connects[con_id] = connect | ||
|
||
def unregister_connect(self, con_id): | ||
del self._connects[con_id] | ||
|
||
def get_connect(self, con_id=None): | ||
return self._connects.get(con_id) | ||
|
||
def get_connects_by_instance(self, instance_id): | ||
connects = [] | ||
for connect in self._connects.values(): | ||
if connect.instance_id == instance_id: | ||
connects.append(connect) | ||
|
||
return connects |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import logging | ||
import os | ||
|
||
import aexpect | ||
from vt_agent.core.data_dir import LOG_DIR | ||
|
||
from virttest import utils_logfile, utils_misc | ||
|
||
LOG = logging.getLogger("avocado.service." + __name__) | ||
|
||
|
||
class Console(object): | ||
def __init__(self, instance_id, console_type, console=None): | ||
self._instance_id = instance_id | ||
self._console_type = console_type | ||
self._console = console | ||
|
||
@property | ||
def instance_id(self): | ||
return self._instance_id | ||
|
||
|
||
class SerialConsole(Console): | ||
def __init__(self, instance_id, console=None): | ||
super(SerialConsole, self).__init__(instance_id, "serial", console) | ||
|
||
def __getattr__(self, item): | ||
if self._console: | ||
return getattr(self._console, item) | ||
|
||
|
||
class ConsoleManager(object): | ||
""" | ||
Manager the connection to the console for the VM | ||
""" | ||
|
||
def __init__(self): | ||
self._consoles = {} | ||
|
||
@staticmethod | ||
def create_console(name, instance_id, console_type, file_name, params={}): | ||
if console_type == "serial": | ||
log_name = os.path.join(LOG_DIR, f"{console_type}-{name}-{instance_id}.log") | ||
serial_session = aexpect.ShellSession( | ||
"nc -U %s" % file_name, | ||
auto_close=False, | ||
output_func=utils_logfile.log_line, | ||
output_params=(log_name,), | ||
prompt=params.get("shell_prompt", "[\#\$]"), | ||
status_test_command=params.get("status_test_command", "echo $?"), | ||
encoding="UTF-8", | ||
) | ||
return SerialConsole(instance_id, console=serial_session) | ||
elif console_type == "vnc": | ||
raise NotImplementedError() | ||
elif console_type == "spice": | ||
raise NotImplementedError() | ||
else: | ||
raise NotImplementedError("Not support console type %s" % console_type) | ||
|
||
def register_console(self, con_id, console): | ||
if con_id in self._consoles: | ||
raise ValueError | ||
self._consoles[con_id] = console | ||
|
||
def unregister_console(self, con_id): | ||
del self._consoles[con_id] | ||
|
||
def get_console(self, con_id): | ||
return self._consoles.get(con_id) | ||
|
||
def get_consoles_by_instance(self, instance_id): | ||
consoles = [] | ||
for console in self._consoles.values(): | ||
if console.instance_id == instance_id: | ||
consoles.append(console) | ||
|
||
return consoles |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import connect, serial, vmm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import logging | ||
|
||
from managers import connect_mgr, vmm | ||
|
||
from virttest import utils_misc | ||
from virttest.qemu_devices import qdevices | ||
|
||
VMM = vmm.VirtualMachinesManager() | ||
LOG = logging.getLogger("avocado.service." + __name__) | ||
|
||
|
||
def open_connect(instance_id, name, protocol, log_file=None): | ||
devices = VMM.get_instance(instance_id).get("devices") | ||
for device in devices: | ||
if isinstance(device, qdevices.CharDevice): | ||
if name == device.get_qid(): | ||
client_params = device.params | ||
break | ||
else: | ||
raise ValueError(f"Not found the qemu client params for {name}") | ||
connect = connect_mgr.create_connect( | ||
instance_id, "qemu", name, protocol, client_params, log_file | ||
) | ||
connect_id = utils_misc.generate_random_string(16) | ||
connect_mgr.register_connect(connect_id, connect) | ||
return connect_id | ||
|
||
|
||
def is_connected(instance_id, name): | ||
connects = connect_mgr.get_connects_by_instance(instance_id) | ||
for connect in connects: | ||
if connect.name == name: | ||
return True | ||
return False | ||
|
||
|
||
def close_connect(connect_id): | ||
connect = connect_mgr.get_connect(connect_id) | ||
return connect.close() | ||
|
||
|
||
def execute_connect_data( | ||
connect_id, data, timeout=None, debug=False, fd=None, data_format=None | ||
): | ||
connect = connect_mgr.get_connect(connect_id) | ||
LOG.info( | ||
f"<Instance: {connect.instance_id}; Monitor: {connect.name}> " | ||
f"Executing {connect.protocol} connect data: {data}" | ||
) | ||
return connect.execute_data(data, timeout, debug, fd, data_format) | ||
|
||
|
||
def get_connect_events(connect_id): | ||
connect = connect_mgr.get_connect(connect_id) | ||
return connect.get_events() | ||
|
||
|
||
def get_connect_event(connect_id, name): | ||
connect = connect_mgr.get_connect(connect_id) | ||
return connect.get_event(name) | ||
|
||
|
||
def clear_connect_events(connect_id): | ||
connect = connect_mgr.get_connect(connect_id) | ||
return connect.clear_events() | ||
|
||
|
||
def clear_connect_event(connect_id, name): | ||
connect = connect_mgr.get_connect(connect_id) | ||
return connect.clear_event(name) | ||
|
||
|
||
def is_responsive(connect_id): | ||
connect = connect_mgr.get_connect(connect_id) | ||
return connect.is_responsive() | ||
|
||
|
||
def get_monitor_log_files(monitor_id): | ||
monitor = connect_mgr.get_connect(monitor_id) | ||
return [log_file for log_file in monitor.open_log_files] |
Oops, something went wrong.