1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-23 17:34:17 +03:00

adding spice support for proxmox

This commit is contained in:
Adolfo Gómez García 2022-10-14 02:07:12 +02:00
parent bf635a5e9a
commit 7769351d42
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
4 changed files with 98 additions and 35 deletions

View File

@ -513,8 +513,7 @@ class ProxmoxClient:
@ensureConected
# @allowCache('vmc', CACHE_DURATION, cachingArgs=[1, 2], cachingKWArgs=['vmId', 'node'], cachingKeyFnc=cachingKeyHelper)
def getVmConfiguration(
self, vmId: int, node: typing.Optional[str] = None):
def getVmConfiguration(self, vmId: int, node: typing.Optional[str] = None):
node = node or self.getVmInfo(vmId).node
return types.VMConfiguration.fromDict(
self._get('nodes/{}/qemu/{}/config'.format(node, vmId))['data']
@ -522,16 +521,20 @@ class ProxmoxClient:
@ensureConected
def setVmMac(
self, vmId: int, mac: str, netid: typing.Optional[str] = None, node: typing.Optional[str] = None
self,
vmId: int,
mac: str,
netid: typing.Optional[str] = None,
node: typing.Optional[str] = None,
) -> None:
node = node or self.getVmInfo(vmId).node
# First, read current configuration and extract network configuration
config = self._get('nodes/{}/qemu/{}/config'.format(node, vmId))['data']
if netid not in config:
# Get first network interface (netX where X is a number)
netid = next(
(k for k in config if k.startswith('net') and k[3:].isdigit()), None
)
netid = next(
(k for k in config if k.startswith('net') and k[3:].isdigit()), None
)
if not netid:
raise ProxmoxError('No network interface found')
@ -546,7 +549,7 @@ class ProxmoxClient:
'nodes/{}/qemu/{}/config'.format(node, vmId),
data=[(netid, netdata)],
)
@ensureConected
def startVm(self, vmId: int, node: typing.Optional[str] = None) -> types.UPID:
# if exitstatus is "OK" or contains "already running", all is fine
@ -661,3 +664,36 @@ class ProxmoxClient:
return [
types.PoolInfo.fromDict(nodeStat) for nodeStat in self._get('pools')['data']
]
@ensureConected
def getConsoleConnection(
self, vmId: int, node: typing.Optional[str] = None
) -> typing.Optional[typing.MutableMapping[str, typing.Any]]:
"""
Gets the connetion info for the specified machine
"""
node = node or self.getVmInfo(vmId).node
res = self._post(f'nodes/{node}/qemu/{vmId}/spiceproxy')['data']
return {
'type': res['type'],
'proxy': res['proxy'],
'address': res['host'],
'port': res.get('port', None),
'secure_port': res['tls-port'],
'cert_subject': res['host-subject'],
'ticket': {'value': res['password'], 'expiry': ''},
}
# Sample data:
# 'data': {'proxy': 'http://pvealone.dkmon.com:3128',
# 'release-cursor': 'Ctrl+Alt+R',
# 'host': 'pvespiceproxy:63489cf9:101:pvealone::c934cf7f7570012bbebab9e1167402b6471aae16',
# 'delete-this-file': 1,
# 'secure-attention': 'Ctrl+Alt+Ins',
# 'title': 'VM 101 - VM-1',
# 'password': '31a189dd71ce859867e28dd68ba166a701e77eed',
# 'type': 'spice',
# 'toggle-fullscreen': 'Shift+F11',
# 'host-subject': 'OU=PVE Cluster Node,O=Proxmox Virtual Environment,CN=pvealone.dkmon.com',
# 'tls-port': 61000,
# 'ca': '-----BEGIN CERTIFICATE-----\\n......\\n-----END CERTIFICATE-----\\n'}}

View File

@ -296,8 +296,7 @@ class ProxmoxProvider(
def getConsoleConnection(
self, machineId: str
) -> typing.Optional[typing.MutableMapping[str, typing.Any]]:
# TODO: maybe proxmox also supports "spice"? for future release...
return None
return self.__getApi().getConsoleConnection(machineId)
def getNewVmId(self) -> int:
while True: # look for an unused VmId

View File

@ -48,6 +48,7 @@ toggle-fullscreen=shift+f11
release-cursor=shift+f12
secure-attention=ctrl+alt+end
{secure_channel}
{proxy}
'''
@ -65,6 +66,7 @@ class RemoteViewerFile:
usb_auto_share: bool = True
new_usb_auto_share: bool = False
delete_file: bool = True
proxy: str = ''
def __init__(
self,
@ -106,6 +108,8 @@ class RemoteViewerFile:
'\n', '\\n'
) # So we get '\\n' and script works fine after replacement
# If proxy is set
return TEMPLATE.format(
type=self.connectionType,
host=self.host,
@ -123,4 +127,5 @@ class RemoteViewerFile:
secure_channel='secure-channels=main;inputs;cursor;playback;record;display;usbredir;smartcard'
if tls_port != '-1'
else '',
proxy=self.proxy,
)

View File

@ -122,34 +122,57 @@ class TSPICETransport(BaseSpiceTransport):
# Spice connection
con = userServiceInstance.getConsoleConnection()
# We MAY need two tickets, one for 'insecure' port an one for secure
ticket = ''
if con['port']:
ticket = TicketStore.create_for_tunnel(
userService=userService,
port=int(con['port']),
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
ticket_secure = ''
if con['secure_port']:
ticket_secure = TicketStore.create_for_tunnel(
userService=userService,
port=int(con['secure_port']),
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
tunHost, tunPort = self.tunnelServer.value.split(':')
r = RemoteViewerFile(
'127.0.0.1',
'{port}',
'{secure_port}',
con['ticket']['value'], # This is secure ticket from kvm, not UDS ticket
self.serverCertificate.value.strip(),
con['cert_subject'],
fullscreen=self.fullScreen.isTrue(),
)
# We MAY need two tickets, one for 'insecure' port an one for secure
ticket = ''
ticket_secure = ''
if 'proxy' not in con:
if con['port']:
ticket = TicketStore.create_for_tunnel(
userService=userService,
port=int(con['port']),
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
if con['secure_port']:
ticket_secure = TicketStore.create_for_tunnel(
userService=userService,
port=int(con['secure_port']),
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
r = RemoteViewerFile(
'127.0.0.1',
'{port}',
'{secure_port}',
con['ticket']['value'], # This is secure ticket from kvm, not UDS ticket
con.get('ca', self.serverCertificate.value.strip()),
con['cert_subject'],
fullscreen=self.fullScreen.isTrue(),
)
else:
# extract host and port from proxy url
host, port = con['proxy'].split('://')[1].split(':')[0:2]
ticket = TicketStore.create_for_tunnel(
userService=userService,
host=host,
port=int(port),
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
r = RemoteViewerFile(
con.get('address'),
con.get('port',),
con.get('secure_port'),
con['ticket']['value'], # password
con.get('ca', self.serverCertificate.value.strip()),
con['cert_subject'],
fullscreen=self.fullScreen.isTrue(),
)
# Set proxy to 127.0.0.1:{port}
r.proxy = con['proxy'].split('://')[0] + '://127.0.0.1:{port}'
r.usb_auto_share = self.usbShare.isTrue()
r.new_usb_auto_share = self.autoNewUsbShare.isTrue()
r.smartcard = self.smartCardRedirect.isTrue()