1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-11-01 12:04:15 +00:00
webvirtcloud/console/socketiod

197 lines
5.2 KiB
Python
Executable file

#!/usr/bin/env python3
import os
import sys
import logging
import django
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
ROOT_PATH = os.path.abspath(os.path.join(DIR_PATH, '..', ''))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webvirtcloud.settings')
CERT = DIR_PATH + '/cert.pem'
if ROOT_PATH not in sys.path:
sys.path.append(ROOT_PATH)
django.setup()
import re
import tempfile
import io
import socket
import socketio
import pty
import select
import subprocess
import struct
import fcntl
import termios
import signal
import eventlet
import atexit
import tty
import termios
import libvirt
#from six.moves import http_cookies as Cookie
from http import cookies as Cookie
from webvirtcloud.settings import SOCKETIO_PORT, SOCKETIO_HOST
from vrtManager.connection import CONN_SSH, CONN_SOCKET
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-v",
"--verbose",
dest="verbose",
action="store_true",
help="Verbose mode",
default=False)
parser.add_option("-d",
"--debug",
dest="debug",
action="store_true",
help="Debug mode",
default=False)
parser.add_option("-H",
"--host",
dest="host",
action="store",
help="Listen host",
default=SOCKETIO_HOST)
parser.add_option("-p",
"--port",
dest="port",
action="store",
help="Listen port",
default=SOCKETIO_PORT or 6081)
(options, args) = parser.parse_args()
FORMAT = "%(asctime)s - %(name)s - %(levelname)s : %(message)s"
if options.debug:
logging.basicConfig(level=logging.DEBUG, format=FORMAT)
options.verbose = True
elif options.verbose:
logging.basicConfig(level=logging.INFO, format=FORMAT)
else:
logging.basicConfig(level=logging.WARNING, format=FORMAT)
async_mode = "eventlet"
sio = socketio.Server(async_mode=async_mode, cors_allowed_origins=[])
fd = None
child_pid = None
def get_connection_infos(token):
from instances.models import Instance
from vrtManager.instance import wvmInstance
try:
temptoken = token.split('-', 1)
host = int(temptoken[0])
uuid = temptoken[1]
instance = Instance.objects.get(compute_id=host, uuid=uuid)
conn = wvmInstance(instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
instance.name)
except Exception as e:
logging.error(
'Fail to retrieve console connection infos for token %s : %s' % (token, e))
raise
return (instance, conn)
def set_winsize(fd, row, col, xpix=0, ypix=0):
winsize = struct.pack("HHHH", row, col, xpix, ypix)
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
def read_and_forward_pty_output():
global fd
max_read_bytes = 1024 * 20
while True:
sio.sleep(0.01)
if fd:
timeout_sec = 0
(data_ready, _, _) = select.select([fd], [], [], timeout_sec)
if data_ready:
output = os.read(fd, max_read_bytes).decode()
sio.emit("pty_output", {"output": output})
else:
return
@sio.event
def resize(sid, message):
global fd
if fd:
set_winsize(fd, message["rows"], message["cols"])
@sio.event
def pty_input(sid, message):
global fd
if fd:
os.write(fd, message["input"].encode())
@sio.event
def disconnect_request(sid):
sio.disconnect(sid)
@sio.event
def connect(sid, environ):
global fd
global child_pid
hcookie = environ.get('HTTP_COOKIE')
if hcookie:
cookie = Cookie.SimpleCookie()
for hcookie_part in hcookie.split(';'):
hcookie_part = hcookie_part.lstrip()
try:
cookie.load(hcookie_part)
except Cookie.CookieError:
logging.warn('Found malformed cookie')
else:
if 'token' in cookie:
token = cookie['token'].value
if child_pid:
# already started child process, don't start another
# write a new line so that when a client refresh the shell prompt is printed
fd.write("\n")
return
# create child process attached to a pty we can read from and write to
(child_pid, fd) = pty.fork()
if child_pid == 0:
(instance, conn) = get_connection_infos(token)
uuid = conn.get_uuid()
uri = conn.wvm.getURI()
subprocess.run(['conf/daemon/consolecallback', uri, uuid])
else:
# this is the parent process fork.
sio.start_background_task(target=read_and_forward_pty_output)
@sio.event
def disconnect(sid):
global fd
global child_pid
# kill pty process
os.kill(child_pid,signal.SIGKILL)
os.wait()
# reset the variables
fd = None
child_pid = None
app = socketio.WSGIApp(sio)
import eventlet
eventlet.wsgi.server(eventlet.listen((options.host,int(options.port))), app)