mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
[XEND] Preliminary console support in Xen API
Made serial/vnc consoles a 'fake' device so that we can take advantage of storing state information in xenstore. Signed-off-by: Alastair Tse <atse@xensource.com>
This commit is contained in:
1 parent
4b3c5bc127
commit
690dd07a38
7 files changed
+164
-24
No files matched your search
@@ -40,6 +40,7 @@ VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\
|
||||
VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
|
||||
TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
|
||||
VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
|
||||
CONSOLE_LIST_FORMAT = '%(uuid)-36s %(protocol)-8s %(uri)-32s'
|
||||
|
||||
COMMANDS = {
|
||||
'host-info': ('', 'Get Xen Host Info'),
|
||||
@@ -485,7 +486,8 @@ def xapi_vbd_list(args, async = False):
|
||||
for vbd in vbds:
|
||||
vbd_struct = execute(server, 'VBD.get_record', (session, vbd))
|
||||
print VBD_LIST_FORMAT % vbd_struct
|
||||
|
||||
|
||||
|
||||
def xapi_vbd_stats(args, async = False):
|
||||
server, session = connect()
|
||||
domname = args[0]
|
||||
@@ -519,6 +521,31 @@ def xapi_vif_list(args, async = False):
|
||||
vif_struct = execute(server, 'VIF.get_record', (session, vif))
|
||||
pprint(vif_struct)
|
||||
|
||||
def xapi_console_list(args, async = False):
|
||||
server, session = connect()
|
||||
opts, args = parse_args('vdi-list', args, set_defaults = True)
|
||||
is_long = opts and opts.long
|
||||
|
||||
domname = args[0]
|
||||
|
||||
dom_uuid = resolve_vm(server, session, domname)
|
||||
consoles = execute(server, 'VM.get_consoles', (session, dom_uuid))
|
||||
|
||||
if not is_long:
|
||||
print CONSOLE_LIST_FORMAT % {'protocol': 'Protocol',
|
||||
'uri': 'URI',
|
||||
'uuid': 'UUID'}
|
||||
|
||||
for console in consoles:
|
||||
console_struct = execute(server, 'console.get_record',
|
||||
(session, console))
|
||||
print CONSOLE_LIST_FORMAT % console_struct
|
||||
else:
|
||||
for console in consoles:
|
||||
console_struct = execute(server, 'console.get_record',
|
||||
(session, console))
|
||||
pprint(console_struct)
|
||||
|
||||
|
||||
def xapi_vdi_list(args, async = False):
|
||||
opts, args = parse_args('vdi-list', args, set_defaults = True)
|
||||
|
||||
@@ -228,6 +228,18 @@ def valid_vtpm(func):
|
||||
_check_ref(lambda r: XendDomain.instance().is_valid_dev('vtpm', r),
|
||||
'VTPM_HANDLE_INVALID', func, *args, **kwargs)
|
||||
|
||||
|
||||
def valid_console(func):
|
||||
"""Decorator to verify if console_ref is valid before calling method.
|
||||
|
||||
@param func: function with params: (self, session, console_ref, ...)
|
||||
@rtype: callable object
|
||||
"""
|
||||
return lambda *args, **kwargs: \
|
||||
_check_ref(lambda r: XendDomain.instance().is_valid_dev('console',
|
||||
r),
|
||||
'CONSOLE_HANDLE_INVALID', func, *args, **kwargs)
|
||||
|
||||
def valid_sr(func):
|
||||
"""Decorator to verify if sr_ref is valid before calling method.
|
||||
|
||||
@@ -346,6 +358,7 @@ class XendAPI(object):
|
||||
'VIF' : valid_vif,
|
||||
'VDI' : valid_vdi,
|
||||
'VTPM' : valid_vtpm,
|
||||
'console' : valid_console,
|
||||
'SR' : valid_sr,
|
||||
'PIF' : valid_pif,
|
||||
'task' : valid_task,
|
||||
@@ -983,14 +996,18 @@ class XendAPI(object):
|
||||
def VM_get_VTPMs(self, session, vm_ref):
|
||||
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
return xen_api_success(dom.get_vtpms())
|
||||
|
||||
def VM_get_consoles(self, session, vm_ref):
|
||||
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
return xen_api_success(dom.get_consoles())
|
||||
|
||||
def VM_get_PCI_bus(self, session, vm_ref):
|
||||
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
return xen_api_todo() # unsupported by xc
|
||||
return dom.get_pci_bus()
|
||||
|
||||
def VM_get_tools_version(self, session, vm_ref):
|
||||
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
return xen_api_todo()
|
||||
return dom.get_tools_version()
|
||||
|
||||
# attributes (rw)
|
||||
def VM_get_name_label(self, session, vm_ref):
|
||||
@@ -1784,6 +1801,54 @@ class XendAPI(object):
|
||||
vtpms = reduce(lambda x, y: x + y, vtpms)
|
||||
return xen_api_success(vtpms)
|
||||
|
||||
# Xen API: Class console
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
console_attr_ro = ['uri', 'protocol', 'VM']
|
||||
console_attr_rw = []
|
||||
|
||||
def console_get_all(self, session):
|
||||
xendom = XendDomain.instance()
|
||||
cons = [d.get_consoles() for d in XendDomain.instance().list('all')]
|
||||
cons = reduce(lambda x, y: x + y, cons)
|
||||
return xen_api_success(cons)
|
||||
|
||||
def console_get_uri(self, session, console_ref):
|
||||
return xen_api_success(xendom.get_dev_property_by_uuid('console',
|
||||
console_ref,
|
||||
'uri'))
|
||||
|
||||
def console_get_protocol(self, session, console_ref):
|
||||
return xen_api_success(xendom.get_dev_property_by_uuid('console',
|
||||
console_ref,
|
||||
'protocol'))
|
||||
|
||||
def console_get_VM(self, session, console_ref):
|
||||
xendom = XendDomain.instance()
|
||||
vm = xendom.get_vm_with_dev_uuid('console', console_ref)
|
||||
return xen_api_success(vm.get_uuid())
|
||||
|
||||
# object methods
|
||||
def console_get_record(self, session, console_ref):
|
||||
xendom = XendDomain.instance()
|
||||
vm = xendom.get_vm_with_dev_uuid('console', console_ref)
|
||||
if not vm:
|
||||
return xen_api_error(['CONSOLE_HANDLE_INVALID', console_ref])
|
||||
cfg = vm.get_dev_xenapi_config('console', console_ref)
|
||||
if not cfg:
|
||||
return xen_api_error(['CONSOLE_HANDLE_INVALID', console_ref])
|
||||
|
||||
valid_console_keys = self.console_attr_ro + self.console_attr_rw + \
|
||||
self.Base_attr_ro + self.Base_attr_rw
|
||||
|
||||
return_cfg = {}
|
||||
for k in cfg.keys():
|
||||
if k in valid_console_keys:
|
||||
return_cfg[k] = cfg[k]
|
||||
|
||||
return xen_api_success(return_cfg)
|
||||
|
||||
|
||||
# Xen API: Class SR
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
@@ -75,3 +75,4 @@ XEN_API_VDI_TYPE = ['system', 'user', 'ephemeral']
|
||||
XEN_API_DRIVER_TYPE = ['ioemu', 'paravirtualised']
|
||||
XEN_API_VBD_TYPE = ['CD', 'Disk']
|
||||
XEN_API_TASK_STATUS_TYPE = ['pending', 'success', 'failure']
|
||||
XEN_API_CONSOLE_PROTOCOL = ['vt100', 'rfb', 'rdp']
|
||||
@@ -918,8 +918,7 @@ class XendConfig(dict):
|
||||
if target == None:
|
||||
target = self
|
||||
|
||||
if dev_type not in XendDevices.valid_devices() and \
|
||||
dev_type not in XendDevices.pseudo_devices():
|
||||
if dev_type not in XendDevices.valid_devices():
|
||||
raise XendConfigError("XendConfig: %s not a valid device type" %
|
||||
dev_type)
|
||||
|
||||
@@ -927,10 +926,10 @@ class XendConfig(dict):
|
||||
raise XendConfigError("XendConfig: device_add requires some "
|
||||
"config.")
|
||||
|
||||
if cfg_sxp:
|
||||
log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
|
||||
if cfg_xenapi:
|
||||
log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
|
||||
#if cfg_sxp:
|
||||
# log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
|
||||
#if cfg_xenapi:
|
||||
# log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
|
||||
|
||||
if cfg_sxp:
|
||||
if sxp.child0(cfg_sxp) == 'device':
|
||||
@@ -971,7 +970,12 @@ class XendConfig(dict):
|
||||
target['vbd_refs'] = []
|
||||
if dev_uuid not in target['vbd_refs']:
|
||||
target['vbd_refs'].append(dev_uuid)
|
||||
|
||||
elif dev_type in ('console',):
|
||||
if 'console_refs' not in target:
|
||||
target['console_refs'] = []
|
||||
if dev_uuid not in target['console_refs']:
|
||||
target['console_refs'].append(dev_uuid)
|
||||
|
||||
return dev_uuid
|
||||
|
||||
if cfg_xenapi:
|
||||
@@ -1031,7 +1035,25 @@ class XendConfig(dict):
|
||||
|
||||
# no valid device to add
|
||||
return ''
|
||||
|
||||
|
||||
def console_add(self, protocol, uri):
|
||||
dev_uuid = uuid.createString()
|
||||
dev_info = {
|
||||
'uuid': dev_uuid,
|
||||
'protocol': protocol,
|
||||
'uri': uri
|
||||
}
|
||||
if 'devices' not in self:
|
||||
self['devices'] = {}
|
||||
|
||||
self['devices'][dev_uuid] = ('console', dev_info)
|
||||
self['console_refs'].append(dev_uuid)
|
||||
return dev_info
|
||||
|
||||
def console_get_all(self, protocol):
|
||||
consoles = [dinfo for dtype, dinfo in self['devices'].values()
|
||||
if dtype == 'console']
|
||||
return [c for c in consoles if c.get('protocol') == protocol]
|
||||
|
||||
def device_update(self, dev_uuid, cfg_sxp):
|
||||
"""Update an existing device with the new configuration.
|
||||
@@ -1211,7 +1233,7 @@ class XendConfig(dict):
|
||||
self[apikey] = val
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# debugging
|
||||
#
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif, vfbif
|
||||
from xen.xend.server.BlktapController import BlktapController
|
||||
from xen.xend.server.ConsoleController import ConsoleController
|
||||
|
||||
|
||||
class XendDevices:
|
||||
""" An ugly halfway point between the module local device name
|
||||
@@ -43,6 +45,7 @@ class XendDevices:
|
||||
'tap': BlktapController,
|
||||
'vfb': vfbif.VfbifController,
|
||||
'vkbd': vfbif.VkbdifController,
|
||||
'console': ConsoleController,
|
||||
}
|
||||
|
||||
#@classmethod
|
||||
@@ -50,11 +53,6 @@ class XendDevices:
|
||||
return cls.controllers.keys()
|
||||
valid_devices = classmethod(valid_devices)
|
||||
|
||||
#@classmethod
|
||||
def pseudo_devices(cls):
|
||||
return ['console']
|
||||
pseudo_devices = classmethod(pseudo_devices)
|
||||
|
||||
#@classmethod
|
||||
def make_controller(cls, name, domain):
|
||||
"""Factory function to make device controllers per domain.
|
||||
|
||||
@@ -682,6 +682,29 @@ class XendDomainInfo:
|
||||
for device in devices:
|
||||
self.info.device_add(device[0], cfg_sxp = device)
|
||||
|
||||
self._update_consoles()
|
||||
|
||||
def _update_consoles(self):
|
||||
if self.domid == None or self.domid == 0:
|
||||
return
|
||||
|
||||
# Update VT100 port if it exists
|
||||
self.console_port = self.readDom('console/port')
|
||||
if self.console_port is not None:
|
||||
serial_consoles = self.info.console_get_all('vt100')
|
||||
if not serial_consoles:
|
||||
cfg = self.info.console_add('vt100', self.console_port)
|
||||
self._createDevice('console', cfg)
|
||||
|
||||
# Update VNC port if it exists
|
||||
vnc_port = self.readDom('console/vnc-port')
|
||||
if vnc_port is not None:
|
||||
vnc_consoles = self.info.console_get_all('rfb')
|
||||
if not vnc_consoles:
|
||||
cfg = self.info.console_add('rfb', 'localhost:%s' %
|
||||
str(vnc_port))
|
||||
self._createDevice('console', cfg)
|
||||
|
||||
#
|
||||
# Function to update xenstore /vm/*
|
||||
#
|
||||
@@ -1892,7 +1915,8 @@ class XendDomainInfo:
|
||||
# TODO: we should eventually get rid of old_dom_states
|
||||
|
||||
self.info.update_config(info)
|
||||
|
||||
self._update_consoles()
|
||||
|
||||
if refresh:
|
||||
self.refreshShutdown(info)
|
||||
|
||||
@@ -1904,11 +1928,11 @@ class XendDomainInfo:
|
||||
ignore_devices = ignore_store,
|
||||
legacy_only = legacy_only)
|
||||
|
||||
if not ignore_store and self.dompath:
|
||||
vnc_port = self.readDom('console/vnc-port')
|
||||
if vnc_port is not None:
|
||||
result.append(['device',
|
||||
['console', ['vnc-port', str(vnc_port)]]])
|
||||
#if not ignore_store and self.dompath:
|
||||
# vnc_port = self.readDom('console/vnc-port')
|
||||
# if vnc_port is not None:
|
||||
# result.append(['device',
|
||||
# ['console', ['vnc-port', str(vnc_port)]]])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class DevController:
|
||||
|
||||
def __init__(self, vm):
|
||||
self.vm = vm
|
||||
|
||||
self.hotplug = True
|
||||
|
||||
def createDevice(self, config):
|
||||
"""Trigger the creation of a device with the given configuration.
|
||||
@@ -151,6 +151,9 @@ class DevController:
|
||||
|
||||
def waitForDevice(self, devid):
|
||||
log.debug("Waiting for %s.", devid)
|
||||
|
||||
if not self.hotplug:
|
||||
return
|
||||
|
||||
status = self.waitForBackend(devid)
|
||||
|
||||
|
||||