Add live VNC information to domain output

Sets in the node daemon, returns via the API, and shows in the CLI,
information about the live VNC listen address and port for VNC-enabled
VMs.

Closes #115
This commit is contained in:
Joshua Boniface 2020-12-20 16:00:55 -05:00
parent 9aeb86246a
commit 1b6613c280
6 changed files with 58 additions and 1 deletions

View File

@ -1023,6 +1023,15 @@ class API_VM_Root(Resource):
console: console:
type: string type: string
descritpion: The serial console type of the VM descritpion: The serial console type of the VM
vnc:
type: object
properties:
listen:
type: string
description: The active VNC listen address or 'None'
port:
type: string
description: The active VNC port or 'None'
emulator: emulator:
type: string type: string
description: The binary emulator of the VM description: The binary emulator of the VM

View File

@ -1071,6 +1071,11 @@ def format_info(config, domain_information, long_output):
ainformation.append('{}vCPUs:{} {}'.format(ansiprint.purple(), ansiprint.end(), domain_information['vcpu'])) ainformation.append('{}vCPUs:{} {}'.format(ansiprint.purple(), ansiprint.end(), domain_information['vcpu']))
ainformation.append('{}Topology (S/C/T):{} {}'.format(ansiprint.purple(), ansiprint.end(), domain_information['vcpu_topology'])) ainformation.append('{}Topology (S/C/T):{} {}'.format(ansiprint.purple(), ansiprint.end(), domain_information['vcpu_topology']))
if domain_information['vnc'].get('listen', 'None') != 'None' and domain_information['vnc'].get('port', 'None') != 'None':
ainformation.append('')
ainformation.append('{}VNC listen:{} {}'.format(ansiprint.purple(), ansiprint.end(), domain_information['vnc']['listen']))
ainformation.append('{}VNC port:{} {}'.format(ansiprint.purple(), ansiprint.end(), domain_information['vnc']['port']))
if long_output is True: if long_output is True:
# Virtualization information # Virtualization information
ainformation.append('') ainformation.append('')

View File

@ -267,6 +267,13 @@ def getInformationFromXML(zk_conn, uuid):
except Exception: except Exception:
domain_profile = None domain_profile = None
try:
domain_vnc = zkhandler.readdata(zk_conn, '/domains/{}/vnc'.format(uuid))
domain_vnc_listen, domain_vnc_port = domain_vnc.split(':')
except Exception:
domain_vnc_listen = 'None'
domain_vnc_port = 'None'
parsed_xml = getDomainXML(zk_conn, uuid) parsed_xml = getDomainXML(zk_conn, uuid)
try: try:
@ -312,6 +319,10 @@ def getInformationFromXML(zk_conn, uuid):
'arch': domain_arch, 'arch': domain_arch,
'machine': domain_machine, 'machine': domain_machine,
'console': domain_console, 'console': domain_console,
'vnc': {
'listen': domain_vnc_listen,
'port': domain_vnc_port
},
'emulator': domain_emulator, 'emulator': domain_emulator,
'features': domain_features, 'features': domain_features,
'disks': domain_disks, 'disks': domain_disks,

View File

@ -207,6 +207,7 @@ def define_vm(zk_conn, config_data, target_node, node_limit, node_selector, node
'/domains/{}/consolelog'.format(dom_uuid): '', '/domains/{}/consolelog'.format(dom_uuid): '',
'/domains/{}/rbdlist'.format(dom_uuid): formatted_rbd_list, '/domains/{}/rbdlist'.format(dom_uuid): formatted_rbd_list,
'/domains/{}/profile'.format(dom_uuid): profile, '/domains/{}/profile'.format(dom_uuid): profile,
'/domains/{}/vnc'.format(dom_uuid): '',
'/domains/{}/xml'.format(dom_uuid): config_data '/domains/{}/xml'.format(dom_uuid): config_data
}) })

View File

@ -1302,6 +1302,19 @@
"description": "The topology of the assigned vCPUs in Sockets/Cores/Threads format", "description": "The topology of the assigned vCPUs in Sockets/Cores/Threads format",
"type": "string" "type": "string"
}, },
"vnc": {
"properties": {
"listen": {
"description": "The active VNC listen address or 'None'",
"type": "string"
},
"port": {
"description": "The active VNC port or 'None'",
"type": "string"
}
},
"type": "object"
},
"xml": { "xml": {
"description": "The raw Libvirt XML definition of the VM", "description": "The raw Libvirt XML definition of the VM",
"type": "string" "type": "string"

View File

@ -27,6 +27,8 @@ import json
from threading import Thread from threading import Thread
from xml.etree import ElementTree
import pvcnoded.zkhandler as zkhandler import pvcnoded.zkhandler as zkhandler
import pvcnoded.common as common import pvcnoded.common as common
@ -208,6 +210,21 @@ class VMInstance(object):
except Exception as e: except Exception as e:
self.logger.out('Error removing domain from list: {}'.format(e), state='e') self.logger.out('Error removing domain from list: {}'.format(e), state='e')
# Update the VNC live data
def update_vnc(self):
if self.dom is not None:
live_xml = ElementTree.fromstring(self.dom.XMLDesc(0))
graphics = live_xml.find('./devices/graphics')
if graphics is not None:
self.logger.out('Updating VNC data', state='i', prefix='Domain {}'.format(self.domuuid))
port = graphics.get('port', '')
listen = graphics.get('listen', '')
zkhandler.writedata(self.zk_conn, {'/domains/{}/vnc'.format(self.domuuid): '{}:{}'.format(listen, port)})
else:
zkhandler.writedata(self.zk_conn, {'/domains/{}/vnc'.format(self.domuuid): ''})
else:
zkhandler.writedata(self.zk_conn, {'/domains/{}/vnc'.format(self.domuuid): ''})
# Start up the VM # Start up the VM
def start_vm(self): def start_vm(self):
# Start the log watcher # Start the log watcher
@ -739,7 +756,8 @@ class VMInstance(object):
self.removeDomainFromList() self.removeDomainFromList()
# Stop the log watcher # Stop the log watcher
self.console_log_instance.stop() self.console_log_instance.stop()
# Update the VNC information
self.update_vnc()
else: else:
# Conditional pass three - Is this VM currently running on this node # Conditional pass three - Is this VM currently running on this node
if running == libvirt.VIR_DOMAIN_RUNNING: if running == libvirt.VIR_DOMAIN_RUNNING: