mirror of
https://github.com/retspen/webvirtcloud
synced 2025-07-31 12:41:08 +00:00
Implement Libvirt Serial Console as Console on WebVirtCloud
This commit is contained in:
parent
f6915ac51f
commit
65dce10ce1
10 changed files with 398 additions and 2 deletions
100
conf/daemon/consolecallback
Executable file
100
conf/daemon/consolecallback
Executable file
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env python3
|
||||
# consolecallback - provide a persistent console that survives guest reboots
|
||||
|
||||
import os
|
||||
import logging
|
||||
import libvirt
|
||||
import tty
|
||||
import termios
|
||||
import atexit
|
||||
from argparse import ArgumentParser
|
||||
from typing import Optional # noqa F401
|
||||
|
||||
|
||||
def reset_term() -> None:
|
||||
termios.tcsetattr(0, termios.TCSADRAIN, attrs)
|
||||
|
||||
|
||||
def error_handler(unused, error) -> None:
|
||||
# The console stream errors on VM shutdown; we don't care
|
||||
if error[0] == libvirt.VIR_ERR_RPC and error[1] == libvirt.VIR_FROM_STREAMS:
|
||||
return
|
||||
logging.warn(error)
|
||||
|
||||
|
||||
class Console(object):
|
||||
def __init__(self, uri: str, uuid: str) -> None:
|
||||
self.uri = uri
|
||||
self.uuid = uuid
|
||||
self.connection = libvirt.open(uri)
|
||||
self.domain = self.connection.lookupByUUIDString(uuid)
|
||||
self.state = self.domain.state(0)
|
||||
self.connection.domainEventRegister(lifecycle_callback, self)
|
||||
self.stream = None # type: Optional[libvirt.virStream]
|
||||
self.run_console = True
|
||||
self.stdin_watch = -1
|
||||
logging.info("%s initial state %d, reason %d",
|
||||
self.uuid, self.state[0], self.state[1])
|
||||
|
||||
|
||||
def check_console(console: Console) -> bool:
|
||||
if (console.state[0] == libvirt.VIR_DOMAIN_RUNNING or console.state[0] == libvirt.VIR_DOMAIN_PAUSED):
|
||||
if console.stream is None:
|
||||
console.stream = console.connection.newStream(libvirt.VIR_STREAM_NONBLOCK)
|
||||
console.domain.openConsole(None, console.stream, 0)
|
||||
console.stream.eventAddCallback(libvirt.VIR_STREAM_EVENT_READABLE, stream_callback, console)
|
||||
else:
|
||||
if console.stream:
|
||||
console.stream.eventRemoveCallback()
|
||||
console.stream = None
|
||||
|
||||
return console.run_console
|
||||
|
||||
|
||||
def stdin_callback(watch: int, fd: int, events: int, console: Console) -> None:
|
||||
readbuf = os.read(fd, 1024)
|
||||
if readbuf.startswith(b""):
|
||||
console.run_console = False
|
||||
return
|
||||
if console.stream:
|
||||
console.stream.send(readbuf)
|
||||
|
||||
|
||||
def stream_callback(stream: libvirt.virStream, events: int, console: Console) -> None:
|
||||
try:
|
||||
assert console.stream
|
||||
received_data = console.stream.recv(1024)
|
||||
except Exception:
|
||||
return
|
||||
os.write(0, received_data)
|
||||
|
||||
|
||||
def lifecycle_callback(connection: libvirt.virConnect, domain: libvirt.virDomain, event: int, detail: int, console: Console) -> None:
|
||||
console.state = console.domain.state(0)
|
||||
logging.info("%s transitioned to state %d, reason %d",
|
||||
console.uuid, console.state[0], console.state[1])
|
||||
|
||||
|
||||
# main
|
||||
parser = ArgumentParser(epilog="Example: %(prog)s 'qemu:///system' '32ad945f-7e78-c33a-e96d-39f25e025d81'")
|
||||
parser.add_argument("uri")
|
||||
parser.add_argument("uuid")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("Escape character is ^]")
|
||||
logging.basicConfig(filename='msg.log', level=logging.DEBUG)
|
||||
logging.info("URI: %s", args.uri)
|
||||
logging.info("UUID: %s", args.uuid)
|
||||
|
||||
libvirt.virEventRegisterDefaultImpl()
|
||||
libvirt.registerErrorHandler(error_handler, None)
|
||||
|
||||
atexit.register(reset_term)
|
||||
attrs = termios.tcgetattr(0)
|
||||
tty.setraw(0)
|
||||
|
||||
console = Console(args.uri, args.uuid)
|
||||
console.stdin_watch = libvirt.virEventAddHandle(0, libvirt.VIR_EVENT_HANDLE_READABLE, stdin_callback, console)
|
||||
|
||||
while check_console(console):
|
||||
libvirt.virEventRunDefaultImpl()
|
||||
|
|
@ -28,8 +28,17 @@ server {
|
|||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
location /socket.io/ {
|
||||
proxy_pass http://wssocketiod;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
|
||||
upstream wsnovncd {
|
||||
server 127.0.0.1:6080;
|
||||
}
|
||||
}
|
||||
upstream wssocketiod {
|
||||
server 127.0.0.1:6081;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,3 +13,4 @@ rwlock==0.0.7
|
|||
websockify==0.10.0
|
||||
zipp==3.6.0
|
||||
ldap3==2.9.1
|
||||
python-socketio==5.7.0
|
||||
|
|
|
|||
|
|
@ -12,4 +12,12 @@ directory=/srv/webvirtcloud
|
|||
user=www-data
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
redirect_stderr=true
|
||||
|
||||
[program:socketiod]
|
||||
command=/srv/webvirtcloud/venv/bin/python3 /srv/webvirtcloud/console/socketiod -d
|
||||
directory=/srv/webvirtcloud
|
||||
user=www-data
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue