ia64/xen-unstable

changeset 13771:3cccf8e64296

[XEND] Merge VFB support for PV and HVM guests.

This patch merges the way VFB are represented inside Xend by making
HVM VNC consoles use the VFB as its configuration object.

It preserves the way options are specified through xm but will create
a new VFB device that is used by image.py to put vnc config into
qemu-dm's command line. The parsing is moved into image.py's
parseDeviceModel() rather than in configVNC().

Through the Xen API, you can create a 'console' of protocol 'rfb' and
end up with a VNC console, on both HVM and PV guests. The location of
the connecting port is stored in the location attribute of the console
object. This is updated on each XendDomainInfo.update() if it
changes.

Also fixes missing read of the vnclisten and HVM_boot from the
config when initialised via xm. Makes sure bootable attribute for VBD
is store as an int when making SXP config.

Signed-off-by: Alastair Tse <atse@xensource.com>
author Alastair Tse <atse@xensource.com>
date Wed Jan 31 13:20:36 2007 +0000 (2007-01-31)
parents 7c992fd3b19b
children 6d38ae7927cf f63e1244b48d b235a7acaf4a
files tools/python/scripts/test_hvm_create.py tools/python/scripts/test_vm_create.py tools/python/scripts/xapi.py tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/image.py tools/python/xen/xend/server/ConsoleController.py tools/python/xen/xend/server/vfbif.py
line diff
     1.1 --- a/tools/python/scripts/test_hvm_create.py	Wed Jan 31 12:58:41 2007 +0000
     1.2 +++ b/tools/python/scripts/test_hvm_create.py	Wed Jan 31 13:20:36 2007 +0000
     1.3 @@ -72,6 +72,12 @@ vif_cfg = {
     1.4      'MTU': 1500,
     1.5  }    
     1.6  
     1.7 +console_cfg = {
     1.8 +    'protocol': 'rfb',
     1.9 +    'other_config': {'vncunused': 1, 'vncpasswd': 'testing'},
    1.10 +}
    1.11 +
    1.12 +
    1.13  import sys
    1.14  import time
    1.15  sys.path.append('/usr/lib/python')
    1.16 @@ -125,6 +131,12 @@ def test_vm_create():
    1.17          vif_cfg['VM'] = vm_uuid
    1.18          vif_uuid = execute(server, 'VIF.create', (session, vif_cfg))
    1.19  
    1.20 +        # Create a console
    1.21 +        console_cfg['VM'] = vm_uuid
    1.22 +        console_uuid = execute(server, 'console.create',
    1.23 +                               (session, console_cfg))
    1.24 +        print console_uuid
    1.25 +
    1.26          # Start the VM
    1.27          execute(server, 'VM.start', (session, vm_uuid, False))
    1.28  
     2.1 --- a/tools/python/scripts/test_vm_create.py	Wed Jan 31 12:58:41 2007 +0000
     2.2 +++ b/tools/python/scripts/test_vm_create.py	Wed Jan 31 13:20:36 2007 +0000
     2.3 @@ -91,6 +91,11 @@ vif_cfg = {
     2.4      'network': '',
     2.5      'MAC': '',
     2.6      'MTU': 1500,
     2.7 +}
     2.8 +
     2.9 +console_cfg = {
    2.10 +    'protocol': 'rfb',
    2.11 +    'other_config': {'vncunused': 1, 'vncpasswd': 'testing'},
    2.12  }    
    2.13  
    2.14  import sys
    2.15 @@ -157,12 +162,18 @@ def test_vm_create():
    2.16          vif_cfg['VM'] = vm_uuid
    2.17          vif_uuid = execute(server, 'VIF.create', (session, vif_cfg))
    2.18  
    2.19 +        # Create a console
    2.20 +        console_cfg['VM'] = vm_uuid
    2.21 +        console_uuid = execute(server, 'console.create',
    2.22 +                               (session, console_cfg))
    2.23 +        print console_uuid
    2.24 +
    2.25          # Start the VM
    2.26          execute(server, 'VM.start', (session, vm_uuid, False))
    2.27  
    2.28          time.sleep(30)
    2.29  
    2.30 -        test_suspend = True
    2.31 +        test_suspend = False
    2.32          if test_suspend:
    2.33              print 'Suspending VM..'
    2.34              execute(server, 'VM.suspend', (session, vm_uuid))
     3.1 --- a/tools/python/scripts/xapi.py	Wed Jan 31 12:58:41 2007 +0000
     3.2 +++ b/tools/python/scripts/xapi.py	Wed Jan 31 13:20:36 2007 +0000
     3.3 @@ -45,7 +45,7 @@ VDI_LIST_FORMAT = '%(name_label)-18s %(u
     3.4  VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
     3.5  TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
     3.6  VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
     3.7 -CONSOLE_LIST_FORMAT = '%(uuid)-36s %(protocol)-8s %(uri)-32s'
     3.8 +CONSOLE_LIST_FORMAT = '%(uuid)-36s %(protocol)-8s %(location)-32s'
     3.9  
    3.10  COMMANDS = {
    3.11      'host-info': ('', 'Get Xen Host Info'),
    3.12 @@ -545,7 +545,7 @@ def xapi_console_list(args, async = Fals
    3.13  
    3.14      if not is_long:
    3.15          print CONSOLE_LIST_FORMAT % {'protocol': 'Protocol',
    3.16 -                                     'uri': 'URI',
    3.17 +                                     'location': 'Location',
    3.18                                       'uuid': 'UUID'}
    3.19  
    3.20          for console in consoles:
     4.1 --- a/tools/python/xen/xend/XendAPI.py	Wed Jan 31 12:58:41 2007 +0000
     4.2 +++ b/tools/python/xen/xend/XendAPI.py	Wed Jan 31 13:20:36 2007 +0000
     4.3 @@ -1835,8 +1835,9 @@ class XendAPI(object):
     4.4      # ----------------------------------------------------------------
     4.5  
     4.6  
     4.7 -    console_attr_ro = ['uri', 'protocol', 'VM']
     4.8 -    console_attr_rw = []
     4.9 +    console_attr_ro = ['location', 'protocol', 'VM']
    4.10 +    console_attr_rw = ['other_config']
    4.11 +    console_funcs = [('create', 'console')]
    4.12      
    4.13      def console_get_all(self, session):
    4.14          xendom = XendDomain.instance()
    4.15 @@ -1844,10 +1845,10 @@ class XendAPI(object):
    4.16          cons = reduce(lambda x, y: x + y, cons)
    4.17          return xen_api_success(cons)
    4.18  
    4.19 -    def console_get_uri(self, session, console_ref):
    4.20 +    def console_get_location(self, session, console_ref):
    4.21          return xen_api_success(xendom.get_dev_property_by_uuid('console',
    4.22                                                                 console_ref,
    4.23 -                                                               'uri'))
    4.24 +                                                               'location'))
    4.25  
    4.26      def console_get_protocol(self, session, console_ref):
    4.27          return xen_api_success(xendom.get_dev_property_by_uuid('console',
    4.28 @@ -1879,6 +1880,22 @@ class XendAPI(object):
    4.29              
    4.30          return xen_api_success(return_cfg)
    4.31  
    4.32 +    def console_create(self, session, console_struct):
    4.33 +        xendom = XendDomain.instance()
    4.34 +        if not xendom.is_valid_vm(console_struct['VM']):
    4.35 +            return xen_api_error(['VM_HANDLE_INVALID', console_struct['VM']])
    4.36 +        
    4.37 +        dom = xendom.get_vm_by_uuid(console_struct['VM'])
    4.38 +        try:
    4.39 +            if 'protocol' not in console_struct:
    4.40 +                return xen_api_error(['CONSOLE_PROTOCOL_INVALID',
    4.41 +                                      'No protocol specified'])
    4.42 +            
    4.43 +            console_ref = dom.create_console(console_struct)
    4.44 +            xendom.managed_config_save(dom)
    4.45 +            return xen_api_success(console_ref)
    4.46 +        except XendError, e:
    4.47 +            return xen_api_error([XEND_ERROR_TODO, str(e)])
    4.48  
    4.49      # Xen API: Class SR
    4.50      # ----------------------------------------------------------------
     5.1 --- a/tools/python/xen/xend/XendConfig.py	Wed Jan 31 12:58:41 2007 +0000
     5.2 +++ b/tools/python/xen/xend/XendConfig.py	Wed Jan 31 13:20:36 2007 +0000
     5.3 @@ -126,6 +126,7 @@ XENAPI_HVM_CFG = {
     5.4      'platform_serial' : 'serial',
     5.5      'platform_localtime': 'localtime',
     5.6      'platform_keymap' : 'keymap',
     5.7 +    'HVM_boot': 'boot',
     5.8  }    
     5.9  
    5.10  # List of XendConfig configuration keys that have no direct equivalent
    5.11 @@ -250,7 +251,8 @@ LEGACY_IMAGE_CFG = [
    5.12      ('sdl', int),
    5.13      ('vncdisplay', int),
    5.14      ('vncunused', int),
    5.15 -    ('vncpasswd', str),    
    5.16 +    ('vncpasswd', str),
    5.17 +    ('vnclisten', str),
    5.18  ]
    5.19  
    5.20  LEGACY_IMAGE_HVM_CFG = [
    5.21 @@ -379,6 +381,7 @@ class XendConfig(dict):
    5.22              'vif_refs': [],
    5.23              'vbd_refs': [],
    5.24              'vtpm_refs': [],
    5.25 +            'other_config': {},
    5.26          }
    5.27          
    5.28          defaults['name_label'] = 'Domain-' + defaults['uuid']
    5.29 @@ -660,6 +663,25 @@ class XendConfig(dict):
    5.30          self['vbd_refs'] = cfg.get('vbd_refs', [])
    5.31          self['vtpm_refs'] = cfg.get('vtpm_refs', [])
    5.32  
    5.33 +        # coalesce hvm vnc frame buffer with vfb config
    5.34 +        if self['image']['type'] == 'hvm' and self['image'].get('vnc', 0):
    5.35 +            # add vfb device if it isn't there already
    5.36 +            has_rfb = False
    5.37 +            for console_uuid in self['console_refs']:
    5.38 +                if self['devices'][console_uuid][1].get('protocol') == 'rfb':
    5.39 +                    has_rfb = True
    5.40 +                    break
    5.41 +
    5.42 +            if not has_rfb:
    5.43 +                dev_config = ['vfb']
    5.44 +                # copy VNC related params from image config to vfb dev conf
    5.45 +                for key in ['vncpasswd', 'vncunused', 'vncdisplay',
    5.46 +                            'vnclisten']:
    5.47 +                    if key in self['image']:
    5.48 +                        dev_config.append([key, self['image'][key]])
    5.49 +
    5.50 +                self.device_add('vfb', cfg_sxp = dev_config)
    5.51 +
    5.52  
    5.53      def _sxp_to_xapi_unsupported(self, sxp_cfg):
    5.54          """Read in an SXP configuration object and populate
    5.55 @@ -756,7 +778,7 @@ class XendConfig(dict):
    5.56  
    5.57                  # currently unsupported options
    5.58                  self['image']['hvm']['device_model'] = LEGACY_DM
    5.59 -                self['image']['vnc'] = 1
    5.60 +                self['image']['vnc'] = 0
    5.61                  self['image']['hvm']['pae'] = 1
    5.62  
    5.63                  if self['platform_enable_audio']:
    5.64 @@ -883,8 +905,9 @@ class XendConfig(dict):
    5.65                                  # store as part of the device config.
    5.66                                  dev_uuid = sxp.child_value(config, 'uuid')
    5.67                                  dev_type, dev_cfg = self['devices'][dev_uuid]
    5.68 -                                config.append(['bootable',
    5.69 -                                               int(dev_cfg['bootable'])])
    5.70 +                                is_bootable = dev_cfg.get('bootable', False)
    5.71 +                                config.append(['bootable', int(is_bootable)])
    5.72 +
    5.73                              sxpr.append(['device', config])
    5.74  
    5.75                          found = True
    5.76 @@ -986,6 +1009,28 @@ class XendConfig(dict):
    5.77                          # bootable.
    5.78                          dev_info['bootable'] = True
    5.79                      target['vbd_refs'].append(dev_uuid)
    5.80 +                    
    5.81 +            elif dev_type == 'vfb':
    5.82 +                # Populate other config with aux data that is associated
    5.83 +                # with vfb
    5.84 +
    5.85 +                other_config = {}
    5.86 +                for key in ['vncunused', 'vncdisplay', 'vnclisten',
    5.87 +                            'vncpasswd', 'type', 'display', 'xauthority',
    5.88 +                            'keymap']:
    5.89 +                    if key in dev_info:
    5.90 +                        other_config[key] = dev_info[key]
    5.91 +                target['devices'][dev_uuid][1]['other_config'] =  other_config
    5.92 +                
    5.93 +                
    5.94 +                if 'console_refs' not in target:
    5.95 +                    target['console_refs'] = []
    5.96 +
    5.97 +                # Treat VFB devices as console devices so they are found
    5.98 +                # through Xen API
    5.99 +                if dev_uuid not in target['console_refs']:
   5.100 +                    target['console_refs'].append(dev_uuid)
   5.101 +
   5.102              elif dev_type == 'console':
   5.103                  if 'console_refs' not in target:
   5.104                      target['console_refs'] = []
   5.105 @@ -1048,50 +1093,117 @@ class XendConfig(dict):
   5.106                  target['devices'][dev_uuid] = (dev_type, dev_info)
   5.107                  target['vtpm_refs'].append(dev_uuid)
   5.108  
   5.109 +            elif dev_type == 'console':
   5.110 +                dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
   5.111 +                dev_info['uuid'] = dev_uuid
   5.112 +                dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
   5.113 +                dev_info['other_config'] = cfg_xenapi.get('other_config', {})
   5.114 +                if dev_info['protocol'] == 'rfb':
   5.115 +                    # collapse other config into devinfo for things
   5.116 +                    # such as vncpasswd, vncunused, etc.                    
   5.117 +                    dev_info.update(cfg_xenapi.get('other_config', {}))
   5.118 +                    dev_info['type'] = 'vnc'                        
   5.119 +                    target['devices'][dev_uuid] = ('vfb', dev_info)
   5.120 +                    target['console_refs'].append(dev_uuid)
   5.121 +
   5.122 +                    # Finally, if we are a pvfb, we need to make a vkbd
   5.123 +                    # as well that is not really exposed to Xen API
   5.124 +                    vkbd_uuid = uuid.createString()
   5.125 +                    target['devices'][vkbd_uuid] = ('vkbd', {})
   5.126 +                    
   5.127 +                elif dev_info['protocol'] == 'vt100':
   5.128 +                    # if someone tries to create a VT100 console
   5.129 +                    # via the Xen API, we'll have to ignore it
   5.130 +                    # because we create one automatically in
   5.131 +                    # XendDomainInfo._update_consoles
   5.132 +                    raise XendConfigError('Creating vt100 consoles via '
   5.133 +                                          'Xen API is unsupported')
   5.134 +
   5.135              return dev_uuid
   5.136  
   5.137          # no valid device to add
   5.138          return ''
   5.139  
   5.140 -    def console_add(self, protocol, uri):
   5.141 +    def console_add(self, protocol, location, other_config = {}):
   5.142          dev_uuid = uuid.createString()
   5.143 -        dev_info = {
   5.144 -            'uuid': dev_uuid,
   5.145 -            'protocol': protocol,
   5.146 -            'uri': uri
   5.147 -        }
   5.148 -        if 'devices' not in self:
   5.149 -            self['devices'] = {}
   5.150 +        if protocol == 'vt100':
   5.151 +            dev_info = {
   5.152 +                'uuid': dev_uuid,
   5.153 +                'protocol': protocol,
   5.154 +                'location': location,
   5.155 +                'other_config': other_config,
   5.156 +            }
   5.157 +
   5.158 +            if 'devices' not in self:
   5.159 +                self['devices'] = {}
   5.160              
   5.161 -        self['devices'][dev_uuid] = ('console', dev_info)
   5.162 -        self['console_refs'].append(dev_uuid)
   5.163 -        return dev_info
   5.164 +            self['devices'][dev_uuid] = ('console', dev_info)
   5.165 +            self['console_refs'].append(dev_uuid)
   5.166 +            return dev_info
   5.167 +
   5.168 +        return {}
   5.169 +
   5.170 +    def console_update(self, console_uuid, key, value):
   5.171 +        for dev_uuid, (dev_type, dev_info) in self['devices'].items():
   5.172 +            if dev_uuid == console_uuid:
   5.173 +                dev_info[key] = value
   5.174 +                break
   5.175  
   5.176      def console_get_all(self, protocol):
   5.177 -        consoles = [dinfo for dtype, dinfo in self['devices'].values()
   5.178 -                    if dtype == 'console']
   5.179 -        return [c for c in consoles if c.get('protocol') == protocol]
   5.180 +        if protocol == 'vt100':
   5.181 +            consoles = [dinfo for dtype, dinfo in self['devices'].values()
   5.182 +                        if dtype == 'console']
   5.183 +            return [c for c in consoles if c.get('protocol') == protocol]
   5.184  
   5.185 -    def device_update(self, dev_uuid, cfg_sxp):
   5.186 +        elif protocol == 'rfb':
   5.187 +            vfbs = [dinfo for dtype, dinfo in self['devices'].values()
   5.188 +                   if dtype == 'vfb']
   5.189 +
   5.190 +            # move all non-console key values to other_config before
   5.191 +            # returning console config
   5.192 +            valid_keys = ['uuid', 'location']
   5.193 +            for vfb in vfbs:
   5.194 +                other_config = {}
   5.195 +                for key, val in vfb.items():
   5.196 +                    if key not in valid_keys:
   5.197 +                        other_config[key] = vfb[key]
   5.198 +                    del vfb[key]
   5.199 +                vfb['other_config'] = other_config
   5.200 +                vfb['protocol'] = 'rfb'
   5.201 +                        
   5.202 +            return vfbs
   5.203 +
   5.204 +        else:
   5.205 +            return []
   5.206 +
   5.207 +    def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
   5.208          """Update an existing device with the new configuration.
   5.209  
   5.210          @rtype: boolean
   5.211          @return: Returns True if succesfully found and updated a device conf
   5.212          """
   5.213 -        if dev_uuid in self['devices']:
   5.214 +        if dev_uuid in self['devices'] and cfg_sxp:
   5.215              if sxp.child0(cfg_sxp) == 'device':            
   5.216                  config = sxp.child0(cfg_sxp)
   5.217              else:
   5.218                  config = cfg_sxp
   5.219 -                
   5.220 +
   5.221 +            dev_type, dev_info = self['devices'][dev_uuid]
   5.222              for opt_val in config[1:]:
   5.223                  try:
   5.224                      opt, val = opt_val
   5.225 -                    self['devices'][dev_uuid][opt] = val
   5.226 +                    dev_info[opt] = val
   5.227                  except (TypeError, ValueError):
   5.228                      pass # no value for this config option
   5.229 -            
   5.230 +
   5.231 +            self['devices'][dev_uuid] = (dev_type, dev_info)
   5.232              return True
   5.233 +        
   5.234 +        elif dev_uuid in self['devices'] and cfg_xenapi:
   5.235 +            dev_type, dev_info = self['devices'][dev_uuid]
   5.236 +            for key, val in cfg_xenapi.items():
   5.237 +                dev_info[key] = val
   5.238 +            self['devices'][dev_uuid] = (dev_type, dev_info)
   5.239  
   5.240          return False
   5.241  
     6.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Wed Jan 31 12:58:41 2007 +0000
     6.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Wed Jan 31 13:20:36 2007 +0000
     6.3 @@ -695,16 +695,29 @@ class XendDomainInfo:
     6.4              if not serial_consoles:
     6.5                  cfg = self.info.console_add('vt100', self.console_port)
     6.6                  self._createDevice('console', cfg)
     6.7 +            else:
     6.8 +                console_uuid = serial_consoles[0].get('uuid')
     6.9 +                self.info.console_update(console_uuid, 'location',
    6.10 +                                         self.console_port)
    6.11 +                
    6.12  
    6.13 -        # Update VNC port if it exists
    6.14 +        # Update VNC port if it exists and write to xenstore
    6.15          vnc_port = self.readDom('console/vnc-port')
    6.16          if vnc_port is not None:
    6.17 -            vnc_consoles = self.info.console_get_all('rfb')
    6.18 -            if not vnc_consoles:
    6.19 -                cfg = self.info.console_add('rfb', 'localhost:%s' %
    6.20 -                                           str(vnc_port))
    6.21 -                self._createDevice('console', cfg)                
    6.22 +            for dev_uuid, (dev_type, dev_info) in self.info['devices'].items():
    6.23 +                if dev_type == 'vfb':
    6.24 +                    old_location = dev_info.get('location')
    6.25 +                    listen_host = dev_info.get('vnclisten', 'localhost')
    6.26 +                    new_location = '%s:%s' % (listen_host, str(vnc_port))
    6.27 +                    if old_location == new_location:
    6.28 +                        break
    6.29  
    6.30 +                    dev_info['location'] = new_location
    6.31 +                    self.info.device_update(dev_uuid, cfg_xenapi = dev_info)
    6.32 +                    vfb_ctrl = self.getDeviceController('vfb')
    6.33 +                    vfb_ctrl.reconfigureDevice(0, dev_info)
    6.34 +                    break
    6.35 +                
    6.36      #
    6.37      # Function to update xenstore /vm/*
    6.38      #
    6.39 @@ -2017,21 +2030,18 @@ class XendDomainInfo:
    6.40  
    6.41          @rtype: dictionary
    6.42          """
    6.43 -        dev_type_config = self.info['devices'].get(dev_uuid)
    6.44 +        dev_type, dev_config = self.info['devices'].get(dev_uuid, (None, None))
    6.45  
    6.46          # shortcut if the domain isn't started because
    6.47          # the devcontrollers will have no better information
    6.48          # than XendConfig.
    6.49          if self.state in (XEN_API_VM_POWER_STATE_HALTED,):
    6.50 -            if dev_type_config:
    6.51 -                return copy.deepcopy(dev_type_config[1])
    6.52 +            if dev_config:
    6.53 +                return copy.deepcopy(dev_config)
    6.54              return None
    6.55  
    6.56          # instead of using dev_class, we use the dev_type
    6.57          # that is from XendConfig.
    6.58 -        # This will accomdate 'tap' as well as 'vbd'
    6.59 -        dev_type = dev_type_config[0]
    6.60 -        
    6.61          controller = self.getDeviceController(dev_type)
    6.62          if not controller:
    6.63              return None
    6.64 @@ -2040,14 +2050,14 @@ class XendDomainInfo:
    6.65          if not all_configs:
    6.66              return None
    6.67  
    6.68 -        dev_config = copy.deepcopy(dev_type_config[1])
    6.69 +        updated_dev_config = copy.deepcopy(dev_config)
    6.70          for _devid, _devcfg in all_configs.items():
    6.71              if _devcfg.get('uuid') == dev_uuid:
    6.72 -                dev_config.update(_devcfg)
    6.73 -                dev_config['id'] = _devid
    6.74 -                return dev_config
    6.75 +                updated_dev_config.update(_devcfg)
    6.76 +                updated_dev_config['id'] = _devid
    6.77 +                return updated_dev_config
    6.78  
    6.79 -        return dev_config
    6.80 +        return updated_dev_config
    6.81                      
    6.82      def get_dev_xenapi_config(self, dev_class, dev_uuid):
    6.83          config = self.get_dev_config_by_uuid(dev_class, dev_uuid)
    6.84 @@ -2230,6 +2240,21 @@ class XendDomainInfo:
    6.85  
    6.86          return dev_uuid
    6.87  
    6.88 +    def create_console(self, xenapi_console):
    6.89 +        """ Create a console device from a Xen API struct.
    6.90 +
    6.91 +        @return: uuid of device
    6.92 +        @rtype: string
    6.93 +        """
    6.94 +        if self.state not in (DOM_STATE_HALTED,):
    6.95 +            raise VmError("Can only add console to a halted domain.")
    6.96 +
    6.97 +        dev_uuid = self.info.device_add('console', cfg_xenapi = xenapi_console)
    6.98 +        if not dev_uuid:
    6.99 +            raise XendError('Failed to create device')
   6.100 +
   6.101 +        return dev_uuid
   6.102 +
   6.103      def destroy_device_by_uuid(self, dev_type, dev_uuid):
   6.104          if dev_uuid not in self.info['devices']:
   6.105              raise XendError('Device does not exist')
     7.1 --- a/tools/python/xen/xend/image.py	Wed Jan 31 12:58:41 2007 +0000
     7.2 +++ b/tools/python/xen/xend/image.py	Wed Jan 31 13:20:36 2007 +0000
     7.3 @@ -26,6 +26,7 @@ import xen.lowlevel.xc
     7.4  from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS
     7.5  from xen.xend.XendError import VmError, XendError
     7.6  from xen.xend.XendLogging import log
     7.7 +from xen.xend.XendOptions import instance as xenopts
     7.8  from xen.xend.server.netif import randomMAC
     7.9  from xen.xend.xenstore.xswatch import xswatch
    7.10  from xen.xend import arch
    7.11 @@ -340,8 +341,6 @@ class HVMImageHandler(ImageHandler):
    7.12  
    7.13          self.pid = None
    7.14  
    7.15 -        self.dmargs += self.configVNC(imageConfig)
    7.16 -
    7.17          self.pae  = imageConfig['hvm'].get('pae', 0)
    7.18          self.apic  = imageConfig['hvm'].get('apic', 0)
    7.19          self.acpi  = imageConfig['hvm']['devices'].get('acpi', 0)
    7.20 @@ -379,8 +378,8 @@ class HVMImageHandler(ImageHandler):
    7.21          dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
    7.22                     'localtime', 'serial', 'stdvga', 'isa',
    7.23                     'acpi', 'usb', 'usbdevice', 'keymap' ]
    7.24 +        
    7.25          hvmDeviceConfig = vmConfig['image']['hvm']['devices']
    7.26 -
    7.27          ret = ['-vcpus', str(self.vm.getVCpuCount())]
    7.28  
    7.29          for a in dmargs:
    7.30 @@ -439,49 +438,59 @@ class HVMImageHandler(ImageHandler):
    7.31              ret.append("-net")
    7.32              ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge))
    7.33  
    7.34 -        return ret
    7.35  
    7.36 -    def configVNC(self, imageConfig):
    7.37 -        # Handle graphics library related options
    7.38 -        vnc = imageConfig.get('vnc')
    7.39 -        sdl = imageConfig.get('sdl')
    7.40 -        ret = []
    7.41 -        nographic = imageConfig.get('nographic')
    7.42 -
    7.43 -        # get password from VM config (if password omitted, None)
    7.44 -        vncpasswd_vmconfig = imageConfig.get('vncpasswd')
    7.45 -
    7.46 -        if nographic:
    7.47 +        #
    7.48 +        # Find RFB console device, and if it exists, make QEMU enable
    7.49 +        # the VNC console.
    7.50 +        #
    7.51 +        if vmConfig['image'].get('nographic'):
    7.52 +            # skip vnc init if nographic is set
    7.53              ret.append('-nographic')
    7.54              return ret
    7.55  
    7.56 -        if vnc:
    7.57 -            vncdisplay = imageConfig.get('vncdisplay',
    7.58 -                                         int(self.vm.getDomid()))
    7.59 -            vncunused = imageConfig.get('vncunused')
    7.60 -
    7.61 -            if vncunused:
    7.62 -                ret += ['-vncunused']
    7.63 -            else:
    7.64 -                ret += ['-vnc', '%d' % vncdisplay]
    7.65 -
    7.66 -            vnclisten = imageConfig.get('vnclisten')
    7.67 +        vnc_config = {}
    7.68 +        has_vfb = False
    7.69 +        has_vnc = int(vmConfig['image'].get('vnc')) != 0
    7.70 +        for dev_uuid in vmConfig['console_refs']:
    7.71 +            dev_type, dev_info = vmConfig['devices'][devuuid]
    7.72 +            if dev_type == 'rfb':
    7.73 +                vnc_config = dev_info.get('other_config', {})
    7.74 +                has_vfb = True
    7.75 +                break
    7.76  
    7.77 -            if not(vnclisten):
    7.78 -                vnclisten = (xen.xend.XendOptions.instance().
    7.79 -                             get_vnclisten_address())
    7.80 -            if vnclisten:
    7.81 -                ret += ['-vnclisten', vnclisten]
    7.82 +        if not vnc_config:
    7.83 +            for key in ('vncunused', 'vnclisten', 'vncdisplay', 'vncpasswd'):
    7.84 +                if key in vmConfig['image']:
    7.85 +                    vnc_config[key] = vmConfig['image'][key]
    7.86  
    7.87 -            vncpasswd = vncpasswd_vmconfig
    7.88 -            if vncpasswd is None:
    7.89 -                vncpasswd = (xen.xend.XendOptions.instance().
    7.90 -                             get_vncpasswd_default())
    7.91 -                if vncpasswd is None:
    7.92 -                    raise VmError('vncpasswd is not set up in ' +
    7.93 -                                  'VMconfig and xend-config.')
    7.94 -            if vncpasswd != '':
    7.95 -                self.vm.storeVm("vncpasswd", vncpasswd)
    7.96 +        if not has_vfb and not has_vnc:
    7.97 +            ret.append('-nographic')
    7.98 +            return ret
    7.99 +
   7.100 +                    
   7.101 +        if not vnc_config.get('vncunused', 0) and \
   7.102 +               vnc_config.get('vncdisplay', 0):
   7.103 +            ret.append('-vnc')
   7.104 +            ret.append(str(vncdisplay))
   7.105 +        else:
   7.106 +            ret.append('-vncunused')
   7.107 +
   7.108 +        vnclisten = vnc_config.get('vnclisten',
   7.109 +                                   xenopts().get_vnclisten_address())
   7.110 +        ret.append('-vnclisten')
   7.111 +        ret.append(str(vnclisten))
   7.112 +        
   7.113 +        # Store vncpassword in xenstore
   7.114 +        vncpasswd = vnc_config.get('vncpasswd')
   7.115 +        if not vncpasswd:
   7.116 +            vncpasswd = xenopts().get_vncpasswd_default()
   7.117 +                    
   7.118 +        if vncpasswd is None:
   7.119 +            raise VmError('vncpasswd is not setup in vmconfig or '
   7.120 +                          'xend-config.sxp')
   7.121 +
   7.122 +        if vncpasswd != '':
   7.123 +            self.vm.storeVm('vncpasswd', vncpasswd)
   7.124  
   7.125          return ret
   7.126  
     8.1 --- a/tools/python/xen/xend/server/ConsoleController.py	Wed Jan 31 12:58:41 2007 +0000
     8.2 +++ b/tools/python/xen/xend/server/ConsoleController.py	Wed Jan 31 13:20:36 2007 +0000
     8.3 @@ -8,7 +8,7 @@ class ConsoleController(DevController):
     8.4      console devices with persistent UUIDs.
     8.5      """
     8.6  
     8.7 -    valid_cfg = ['uri', 'uuid', 'protocol']
     8.8 +    valid_cfg = ['location', 'uuid', 'protocol']
     8.9  
    8.10      def __init__(self, vm):
    8.11          DevController.__init__(self, vm)
    8.12 @@ -29,3 +29,7 @@ class ConsoleController(DevController):
    8.13  
    8.14      def migrate(self, deviceConfig, network, dst, step, domName):
    8.15          return 0
    8.16 +
    8.17 +    def destroyDevice(self, devid, force):
    8.18 +        DevController.destroyDevice(self, devid, True)
    8.19 +        
     9.1 --- a/tools/python/xen/xend/server/vfbif.py	Wed Jan 31 12:58:41 2007 +0000
     9.2 +++ b/tools/python/xen/xend/server/vfbif.py	Wed Jan 31 13:20:36 2007 +0000
     9.3 @@ -14,7 +14,8 @@ def spawn_detached(path, args, env):
     9.4          os.waitpid(p, 0)
     9.5          
     9.6  CONFIG_ENTRIES = ['type', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused',
     9.7 -                  'display', 'xauthority', 'keymap' ]
     9.8 +                  'display', 'xauthority', 'keymap',
     9.9 +                  'uuid', 'location', 'protocol']
    9.10  
    9.11  class VfbifController(DevController):
    9.12      """Virtual frame buffer controller. Handles all vfb devices for a domain.
    9.13 @@ -27,10 +28,11 @@ class VfbifController(DevController):
    9.14      def getDeviceDetails(self, config):
    9.15          """@see DevController.getDeviceDetails"""
    9.16  
    9.17 -        back = dict([(k, config[k]) for k in CONFIG_ENTRIES
    9.18 +        back = dict([(k, str(config[k])) for k in CONFIG_ENTRIES
    9.19                       if config.has_key(k)])
    9.20  
    9.21 -        return (0, back, {})
    9.22 +        devid = 0
    9.23 +        return (devid, back, {})
    9.24  
    9.25  
    9.26      def getDeviceConfiguration(self, devid):
    9.27 @@ -44,6 +46,10 @@ class VfbifController(DevController):
    9.28  
    9.29      def createDevice(self, config):
    9.30          DevController.createDevice(self, config)
    9.31 +        if self.vm.info.get('HVM_boot'):
    9.32 +            # is HVM, so qemu-dm will handle the vfb.
    9.33 +            return
    9.34 +        
    9.35          std_args = [ "--domid", "%d" % self.vm.getDomid(),
    9.36                       "--title", self.vm.getName() ]
    9.37          t = config.get("type", None)
    9.38 @@ -82,6 +88,42 @@ class VfbifController(DevController):
    9.39          else:
    9.40              raise VmError('Unknown vfb type %s (%s)' % (t, repr(config)))
    9.41  
    9.42 +
    9.43 +    def waitForDevice(self, devid):
    9.44 +        if self.vm.info.get('HVM_boot'):
    9.45 +            log.debug('skip waiting for HVM vfb')
    9.46 +            # is a qemu-dm managed device, don't wait for hotplug for these.
    9.47 +            return
    9.48 +
    9.49 +        DevController.waitForDevice(self, devid)
    9.50 +
    9.51 +
    9.52 +    def reconfigureDevice(self, _, config):
    9.53 +        """ Only allow appending location information of vnc port into
    9.54 +        xenstore."""
    9.55 +
    9.56 +        if 'location' in config:
    9.57 +            (devid, back, front) = self.getDeviceDetails(config)
    9.58 +            self.writeBackend(devid, 'location', config['location'])
    9.59 +            return back.get('uuid')
    9.60 +
    9.61 +        raise VmError('Refusing to reconfigure device vfb:%d' % devid)
    9.62 +
    9.63 +    def destroyDevice(self, devid, force):
    9.64 +        if self.vm.info.get('HVM_boot'):
    9.65 +            # remove the backend xenstore entries for HVM guests no matter
    9.66 +            # what
    9.67 +            DevController.destroyDevice(self, devid, True)
    9.68 +        else:
    9.69 +            DevController.destroyDevice(self, devid, force)
    9.70 +
    9.71 +
    9.72 +    def migrate(self, deviceConfig, network, dst, step, domName):
    9.73 +        if self.vm.info.get('HVM_boot'):        
    9.74 +            return 0
    9.75 +        return DevController.migrate(self, deviceConfig, network, dst, step,
    9.76 +                                     domName)
    9.77 +    
    9.78  class VkbdifController(DevController):
    9.79      """Virtual keyboard controller. Handles all vkbd devices for a domain.
    9.80      """
    9.81 @@ -92,3 +134,24 @@ class VkbdifController(DevController):
    9.82          back = {}
    9.83          front = {}
    9.84          return (devid, back, front)
    9.85 +
    9.86 +    def waitForDevice(self, config):
    9.87 +        if self.vm.info.get('HVM_boot'):
    9.88 +            # is a qemu-dm managed device, don't wait for hotplug for these.
    9.89 +            return
    9.90 +
    9.91 +        DevController.waitForDevice(self, config)
    9.92 +
    9.93 +    def destroyDevice(self, devid, force):
    9.94 +        if self.vm.info.get('HVM_boot'):
    9.95 +            # remove the backend xenstore entries for HVM guests no matter
    9.96 +            # what
    9.97 +            DevController.destroyDevice(self, devid, True)
    9.98 +        else:
    9.99 +            DevController.destroyDevice(self, devid, force)
   9.100 +
   9.101 +    def migrate(self, deviceConfig, network, dst, step, domName):
   9.102 +        if self.vm.info.get('HVM_boot'):        
   9.103 +            return 0
   9.104 +        return DevController.migrate(self, deviceConfig, network, dst, step,
   9.105 +                                     domName)