ia64/xen-unstable

changeset 13630:b111908dd70b

[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>
author Alastair Tse <atse@xensource.com>
date Thu Jan 25 18:54:25 2007 +0000 (2007-01-25)
parents 3bb7136c8fb4
children db3d03dfe92f
files tools/python/scripts/xapi.py tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendAPIConstants.py tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDevices.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/DevController.py
line diff
     1.1 --- a/tools/python/scripts/xapi.py	Thu Jan 25 18:50:08 2007 +0000
     1.2 +++ b/tools/python/scripts/xapi.py	Thu Jan 25 18:54:25 2007 +0000
     1.3 @@ -40,6 +40,7 @@ VDI_LIST_FORMAT = '%(name_label)-18s %(u
     1.4  VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
     1.5  TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
     1.6  VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
     1.7 +CONSOLE_LIST_FORMAT = '%(uuid)-36s %(protocol)-8s %(uri)-32s'
     1.8  
     1.9  COMMANDS = {
    1.10      'host-info': ('', 'Get Xen Host Info'),
    1.11 @@ -485,7 +486,8 @@ def xapi_vbd_list(args, async = False):
    1.12      for vbd in vbds:
    1.13          vbd_struct = execute(server, 'VBD.get_record', (session, vbd))
    1.14          print VBD_LIST_FORMAT % vbd_struct
    1.15 -
    1.16 +        
    1.17 +        
    1.18  def xapi_vbd_stats(args, async = False):
    1.19      server, session = connect()
    1.20      domname = args[0]
    1.21 @@ -519,6 +521,31 @@ def xapi_vif_list(args, async = False):
    1.22              vif_struct = execute(server, 'VIF.get_record', (session, vif))
    1.23              pprint(vif_struct)
    1.24  
    1.25 +def xapi_console_list(args, async = False):
    1.26 +    server, session = connect()
    1.27 +    opts, args = parse_args('vdi-list', args, set_defaults = True)
    1.28 +    is_long = opts and opts.long
    1.29 +    
    1.30 +    domname = args[0]
    1.31 +    
    1.32 +    dom_uuid = resolve_vm(server, session, domname)
    1.33 +    consoles = execute(server, 'VM.get_consoles', (session, dom_uuid))
    1.34 +
    1.35 +    if not is_long:
    1.36 +        print CONSOLE_LIST_FORMAT % {'protocol': 'Protocol',
    1.37 +                                     'uri': 'URI',
    1.38 +                                     'uuid': 'UUID'}
    1.39 +
    1.40 +        for console in consoles:
    1.41 +            console_struct = execute(server, 'console.get_record',
    1.42 +                                     (session, console))
    1.43 +            print CONSOLE_LIST_FORMAT % console_struct
    1.44 +    else:
    1.45 +        for console in consoles:
    1.46 +            console_struct = execute(server, 'console.get_record',
    1.47 +                                     (session, console))
    1.48 +            pprint(console_struct)            
    1.49 +
    1.50  
    1.51  def xapi_vdi_list(args, async = False):
    1.52      opts, args = parse_args('vdi-list', args, set_defaults = True)
     2.1 --- a/tools/python/xen/xend/XendAPI.py	Thu Jan 25 18:50:08 2007 +0000
     2.2 +++ b/tools/python/xen/xend/XendAPI.py	Thu Jan 25 18:54:25 2007 +0000
     2.3 @@ -228,6 +228,18 @@ def valid_vtpm(func):
     2.4             _check_ref(lambda r: XendDomain.instance().is_valid_dev('vtpm', r),
     2.5                        'VTPM_HANDLE_INVALID', func, *args, **kwargs)
     2.6  
     2.7 +
     2.8 +def valid_console(func):
     2.9 +    """Decorator to verify if console_ref is valid before calling method.
    2.10 +
    2.11 +    @param func: function with params: (self, session, console_ref, ...)
    2.12 +    @rtype: callable object
    2.13 +    """
    2.14 +    return lambda *args, **kwargs: \
    2.15 +           _check_ref(lambda r: XendDomain.instance().is_valid_dev('console',
    2.16 +                                                                   r),
    2.17 +                      'CONSOLE_HANDLE_INVALID', func, *args, **kwargs)
    2.18 +
    2.19  def valid_sr(func):
    2.20      """Decorator to verify if sr_ref is valid before calling method.
    2.21  
    2.22 @@ -346,6 +358,7 @@ class XendAPI(object):
    2.23              'VIF'     : valid_vif,
    2.24              'VDI'     : valid_vdi,
    2.25              'VTPM'    : valid_vtpm,
    2.26 +            'console' : valid_console,
    2.27              'SR'      : valid_sr,
    2.28              'PIF'     : valid_pif,
    2.29              'task'    : valid_task,
    2.30 @@ -983,14 +996,18 @@ class XendAPI(object):
    2.31      def VM_get_VTPMs(self, session, vm_ref):
    2.32          dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
    2.33          return xen_api_success(dom.get_vtpms())
    2.34 +
    2.35 +    def VM_get_consoles(self, session, vm_ref):
    2.36 +        dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
    2.37 +        return xen_api_success(dom.get_consoles())
    2.38      
    2.39      def VM_get_PCI_bus(self, session, vm_ref):
    2.40          dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
    2.41 -        return xen_api_todo() # unsupported by xc
    2.42 +        return dom.get_pci_bus()
    2.43      
    2.44      def VM_get_tools_version(self, session, vm_ref):
    2.45          dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
    2.46 -        return xen_api_todo()
    2.47 +        return dom.get_tools_version()
    2.48  
    2.49      # attributes (rw)
    2.50      def VM_get_name_label(self, session, vm_ref):
    2.51 @@ -1784,6 +1801,54 @@ class XendAPI(object):
    2.52          vtpms = reduce(lambda x, y: x + y, vtpms)
    2.53          return xen_api_success(vtpms)
    2.54  
    2.55 +    # Xen API: Class console
    2.56 +    # ----------------------------------------------------------------
    2.57 +
    2.58 +
    2.59 +    console_attr_ro = ['uri', 'protocol', 'VM']
    2.60 +    console_attr_rw = []
    2.61 +    
    2.62 +    def console_get_all(self, session):
    2.63 +        xendom = XendDomain.instance()
    2.64 +        cons = [d.get_consoles() for d in XendDomain.instance().list('all')]
    2.65 +        cons = reduce(lambda x, y: x + y, cons)
    2.66 +        return xen_api_success(cons)
    2.67 +
    2.68 +    def console_get_uri(self, session, console_ref):
    2.69 +        return xen_api_success(xendom.get_dev_property_by_uuid('console',
    2.70 +                                                               console_ref,
    2.71 +                                                               'uri'))
    2.72 +
    2.73 +    def console_get_protocol(self, session, console_ref):
    2.74 +        return xen_api_success(xendom.get_dev_property_by_uuid('console',
    2.75 +                                                               console_ref,
    2.76 +                                                               'protocol'))
    2.77 +    
    2.78 +    def console_get_VM(self, session, console_ref):
    2.79 +        xendom = XendDomain.instance()        
    2.80 +        vm = xendom.get_vm_with_dev_uuid('console', console_ref)
    2.81 +        return xen_api_success(vm.get_uuid())
    2.82 +    
    2.83 +    # object methods
    2.84 +    def console_get_record(self, session, console_ref):
    2.85 +        xendom = XendDomain.instance()
    2.86 +        vm = xendom.get_vm_with_dev_uuid('console', console_ref)
    2.87 +        if not vm:
    2.88 +            return xen_api_error(['CONSOLE_HANDLE_INVALID', console_ref])
    2.89 +        cfg = vm.get_dev_xenapi_config('console', console_ref)
    2.90 +        if not cfg:
    2.91 +            return xen_api_error(['CONSOLE_HANDLE_INVALID', console_ref])
    2.92 +        
    2.93 +        valid_console_keys = self.console_attr_ro + self.console_attr_rw + \
    2.94 +                             self.Base_attr_ro + self.Base_attr_rw
    2.95 +
    2.96 +        return_cfg = {}
    2.97 +        for k in cfg.keys():
    2.98 +            if k in valid_console_keys:
    2.99 +                return_cfg[k] = cfg[k]
   2.100 +            
   2.101 +        return xen_api_success(return_cfg)
   2.102 +
   2.103  
   2.104      # Xen API: Class SR
   2.105      # ----------------------------------------------------------------
     3.1 --- a/tools/python/xen/xend/XendAPIConstants.py	Thu Jan 25 18:50:08 2007 +0000
     3.2 +++ b/tools/python/xen/xend/XendAPIConstants.py	Thu Jan 25 18:54:25 2007 +0000
     3.3 @@ -75,3 +75,4 @@ XEN_API_VDI_TYPE = ['system', 'user', 'e
     3.4  XEN_API_DRIVER_TYPE = ['ioemu', 'paravirtualised']
     3.5  XEN_API_VBD_TYPE = ['CD', 'Disk']
     3.6  XEN_API_TASK_STATUS_TYPE = ['pending', 'success', 'failure']
     3.7 +XEN_API_CONSOLE_PROTOCOL = ['vt100', 'rfb', 'rdp']
     4.1 --- a/tools/python/xen/xend/XendConfig.py	Thu Jan 25 18:50:08 2007 +0000
     4.2 +++ b/tools/python/xen/xend/XendConfig.py	Thu Jan 25 18:54:25 2007 +0000
     4.3 @@ -918,8 +918,7 @@ class XendConfig(dict):
     4.4          if target == None:
     4.5              target = self
     4.6          
     4.7 -        if dev_type not in XendDevices.valid_devices() and \
     4.8 -           dev_type not in XendDevices.pseudo_devices():        
     4.9 +        if dev_type not in XendDevices.valid_devices():
    4.10              raise XendConfigError("XendConfig: %s not a valid device type" %
    4.11                              dev_type)
    4.12  
    4.13 @@ -927,10 +926,10 @@ class XendConfig(dict):
    4.14              raise XendConfigError("XendConfig: device_add requires some "
    4.15                                    "config.")
    4.16  
    4.17 -        if cfg_sxp:
    4.18 -            log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
    4.19 -        if cfg_xenapi:
    4.20 -            log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
    4.21 +        #if cfg_sxp:
    4.22 +        #    log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
    4.23 +        #if cfg_xenapi:
    4.24 +        #    log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
    4.25  
    4.26          if cfg_sxp:
    4.27              if sxp.child0(cfg_sxp) == 'device':
    4.28 @@ -971,7 +970,12 @@ class XendConfig(dict):
    4.29                      target['vbd_refs'] = []
    4.30                  if dev_uuid not in target['vbd_refs']:
    4.31                      target['vbd_refs'].append(dev_uuid)
    4.32 -
    4.33 +            elif dev_type in ('console',):
    4.34 +                if 'console_refs' not in target:
    4.35 +                    target['console_refs'] = []
    4.36 +                if dev_uuid not in target['console_refs']:
    4.37 +                    target['console_refs'].append(dev_uuid)
    4.38 +                    
    4.39              return dev_uuid
    4.40  
    4.41          if cfg_xenapi:
    4.42 @@ -1031,7 +1035,25 @@ class XendConfig(dict):
    4.43  
    4.44          # no valid device to add
    4.45          return ''
    4.46 -        
    4.47 +
    4.48 +    def console_add(self, protocol, uri):
    4.49 +        dev_uuid = uuid.createString()
    4.50 +        dev_info = {
    4.51 +            'uuid': dev_uuid,
    4.52 +            'protocol': protocol,
    4.53 +            'uri': uri
    4.54 +        }
    4.55 +        if 'devices' not in self:
    4.56 +            self['devices'] = {}
    4.57 +            
    4.58 +        self['devices'][dev_uuid] = ('console', dev_info)
    4.59 +        self['console_refs'].append(dev_uuid)
    4.60 +        return dev_info
    4.61 +
    4.62 +    def console_get_all(self, protocol):
    4.63 +        consoles = [dinfo for dtype, dinfo in self['devices'].values()
    4.64 +                    if dtype == 'console']
    4.65 +        return [c for c in consoles if c.get('protocol') == protocol]
    4.66  
    4.67      def device_update(self, dev_uuid, cfg_sxp):
    4.68          """Update an existing device with the new configuration.
    4.69 @@ -1211,7 +1233,7 @@ class XendConfig(dict):
    4.70                      self[apikey] = val
    4.71  
    4.72  
    4.73 -        
    4.74 +
    4.75  #
    4.76  # debugging 
    4.77  #
     5.1 --- a/tools/python/xen/xend/XendDevices.py	Thu Jan 25 18:50:08 2007 +0000
     5.2 +++ b/tools/python/xen/xend/XendDevices.py	Thu Jan 25 18:54:25 2007 +0000
     5.3 @@ -21,6 +21,8 @@
     5.4  
     5.5  from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif, vfbif
     5.6  from xen.xend.server.BlktapController import BlktapController
     5.7 +from xen.xend.server.ConsoleController import ConsoleController
     5.8 +
     5.9  
    5.10  class XendDevices:
    5.11      """ An ugly halfway point between the module local device name
    5.12 @@ -43,6 +45,7 @@ class XendDevices:
    5.13          'tap': BlktapController,
    5.14          'vfb': vfbif.VfbifController,
    5.15          'vkbd': vfbif.VkbdifController,
    5.16 +        'console': ConsoleController,
    5.17      }
    5.18  
    5.19      #@classmethod
    5.20 @@ -51,11 +54,6 @@ class XendDevices:
    5.21      valid_devices = classmethod(valid_devices)
    5.22  
    5.23      #@classmethod
    5.24 -    def pseudo_devices(cls):
    5.25 -        return ['console']
    5.26 -    pseudo_devices = classmethod(pseudo_devices)
    5.27 -
    5.28 -    #@classmethod
    5.29      def make_controller(cls, name, domain):
    5.30          """Factory function to make device controllers per domain.
    5.31  
     6.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Jan 25 18:50:08 2007 +0000
     6.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Jan 25 18:54:25 2007 +0000
     6.3 @@ -682,6 +682,29 @@ class XendDomainInfo:
     6.4              for device in devices:
     6.5                  self.info.device_add(device[0], cfg_sxp = device)
     6.6  
     6.7 +        self._update_consoles()
     6.8 +
     6.9 +    def _update_consoles(self):
    6.10 +        if self.domid == None or self.domid == 0:
    6.11 +            return
    6.12 +
    6.13 +        # Update VT100 port if it exists
    6.14 +        self.console_port = self.readDom('console/port')
    6.15 +        if self.console_port is not None:
    6.16 +            serial_consoles = self.info.console_get_all('vt100')
    6.17 +            if not serial_consoles:
    6.18 +                cfg = self.info.console_add('vt100', self.console_port)
    6.19 +                self._createDevice('console', cfg)
    6.20 +
    6.21 +        # Update VNC port if it exists
    6.22 +        vnc_port = self.readDom('console/vnc-port')
    6.23 +        if vnc_port is not None:
    6.24 +            vnc_consoles = self.info.console_get_all('rfb')
    6.25 +            if not vnc_consoles:
    6.26 +                cfg = self.info.console_add('rfb', 'localhost:%s' %
    6.27 +                                           str(vnc_port))
    6.28 +                self._createDevice('console', cfg)                
    6.29 +
    6.30      #
    6.31      # Function to update xenstore /vm/*
    6.32      #
    6.33 @@ -1892,7 +1915,8 @@ class XendDomainInfo:
    6.34          # TODO: we should eventually get rid of old_dom_states
    6.35  
    6.36          self.info.update_config(info)
    6.37 -
    6.38 +        self._update_consoles()
    6.39 +        
    6.40          if refresh:
    6.41              self.refreshShutdown(info)
    6.42  
    6.43 @@ -1904,11 +1928,11 @@ class XendDomainInfo:
    6.44                                    ignore_devices = ignore_store,
    6.45                                    legacy_only = legacy_only)
    6.46  
    6.47 -        if not ignore_store and self.dompath:
    6.48 -            vnc_port = self.readDom('console/vnc-port')
    6.49 -            if vnc_port is not None:
    6.50 -                result.append(['device',
    6.51 -                               ['console', ['vnc-port', str(vnc_port)]]])
    6.52 +        #if not ignore_store and self.dompath:
    6.53 +        #    vnc_port = self.readDom('console/vnc-port')
    6.54 +        #    if vnc_port is not None:
    6.55 +        #        result.append(['device',
    6.56 +        #                       ['console', ['vnc-port', str(vnc_port)]]])
    6.57  
    6.58          return result
    6.59  
     7.1 --- a/tools/python/xen/xend/server/DevController.py	Thu Jan 25 18:50:08 2007 +0000
     7.2 +++ b/tools/python/xen/xend/server/DevController.py	Thu Jan 25 18:54:25 2007 +0000
     7.3 @@ -75,7 +75,7 @@ class DevController:
     7.4  
     7.5      def __init__(self, vm):
     7.6          self.vm = vm
     7.7 -
     7.8 +        self.hotplug = True
     7.9  
    7.10      def createDevice(self, config):
    7.11          """Trigger the creation of a device with the given configuration.
    7.12 @@ -151,6 +151,9 @@ class DevController:
    7.13  
    7.14      def waitForDevice(self, devid):
    7.15          log.debug("Waiting for %s.", devid)
    7.16 +
    7.17 +        if not self.hotplug:
    7.18 +            return 
    7.19          
    7.20          status = self.waitForBackend(devid)
    7.21