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:
parent
bf635a5e9a
commit
7769351d42
@ -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'}}
|
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user