ia64/xen-unstable

changeset 12127:d34c657e5c74

[XEND] Fix bugs in vbd_create logic when handling VDIs

Attempt to handle 'tap' devices as 'vbd' devices even though the
internal configuration has no idea that 'tap' is a subclass of 'vbd'.

Add option parsing to vbd-create and vdi-create so you can override
the configuration file options.

Signed-off-by: Alastair Tse <atse@xensource.com>
author Alastair Tse <atse@xensource.com>
date Fri Oct 13 17:17:45 2006 +0100 (2006-10-13)
parents a02f6d28eded
children e6162aeb0f89
files tools/python/scripts/xapi.py tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/tools/python/scripts/xapi.py	Fri Oct 13 15:38:13 2006 +0100
     1.2 +++ b/tools/python/scripts/xapi.py	Fri Oct 13 17:17:45 2006 +0100
     1.3 @@ -35,7 +35,9 @@ LOGIN = ('atse', 'passwd')
     1.4  COMMANDS = {
     1.5      'host-info': ('', 'Get Xen Host Info'),
     1.6      'sr-list':   ('', 'List all SRs'),
     1.7 -    'vbd-create': ('<domname> <pycfg>', 'Create VBD attached to domname'),
     1.8 +    'vbd-create': ('<domname> <pycfg> [opts]',
     1.9 +                   'Create VBD attached to domname'),
    1.10 +    'vdi-create': ('<pycfg> [opts]', 'Create a VDI'),
    1.11      'vdi-list'  : ('', 'List all VDI'),
    1.12      'vdi-rename': ('<vdi_uuid> <new_name>', 'Rename VDI'),
    1.13      'vdi-delete': ('<vdi_uuid>', 'Delete VDI'),
    1.14 @@ -57,7 +59,28 @@ OPTIONS = {
    1.15                   {'action':'store_true',
    1.16                    'help':'List all properties of VMs'})
    1.17                 ],
    1.18 -   
    1.19 +    
    1.20 +    'vdi-create': [(('--label',), {'help': 'Name for VDI'}),
    1.21 +                   (('--description',), {'help': 'Description for VDI'}),
    1.22 +                   (('--sector-size',), {'type': 'int',
    1.23 +                                         'help': 'Sector size'}),
    1.24 +                   (('--virtual-size',), {'type': 'int',
    1.25 +                                          'help': 'Size of VDI in sectors'}),
    1.26 +                   (('--type',), {'choices': ['system', 'user', 'ephemeral'],
    1.27 +                                  'help': 'VDI type'}),
    1.28 +                   (('--sharable',), {'action': 'store_true',
    1.29 +                                      'help': 'VDI sharable'}),
    1.30 +                   (('--read-only',), {'action': 'store_true',
    1.31 +                                       'help': 'Read only'})],
    1.32 +    
    1.33 +    'vbd-create': [(('--VDI',), {'help': 'UUID of VDI to attach to.'}),
    1.34 +                   (('--mode',), {'choices': ['RO', 'RW'],
    1.35 +                                  'help': 'device mount mode'}),
    1.36 +                   (('--driver',), {'choices':['paravirtualised', 'ioemu'],
    1.37 +                                    'help': 'Driver for VBD'}),
    1.38 +                   (('--device',), {'help': 'Device name on guest domain'}),
    1.39 +                   (('--image',), {'help': 'Location of drive image.'})]
    1.40 +                   
    1.41  }
    1.42  
    1.43  class OptionError(Exception):
    1.44 @@ -70,6 +93,16 @@ class XenAPIError(Exception):
    1.45  # Extra utility functions
    1.46  #
    1.47  
    1.48 +class IterableValues(Values):
    1.49 +    """Better interface to the list of values from optparse."""
    1.50 +
    1.51 +    def __iter__(self):
    1.52 +        for opt, val in self.__dict__.items():
    1.53 +            if opt[0] == '_' or callable(val):
    1.54 +                continue
    1.55 +            yield opt, val        
    1.56 +
    1.57 +
    1.58  def parse_args(cmd_name, args):
    1.59      argstring, desc = COMMANDS[cmd_name]
    1.60      parser = OptionParser(usage = 'xapi %s %s' % (cmd_name, argstring),
    1.61 @@ -77,8 +110,11 @@ def parse_args(cmd_name, args):
    1.62      if cmd_name in OPTIONS:
    1.63          for optargs, optkwds in OPTIONS[cmd_name]:
    1.64              parser.add_option(*optargs, **optkwds)
    1.65 -            
    1.66 -    (opts, extraargs) = parser.parse_args(list(args))
    1.67 +
    1.68 +    default_values = parser.get_default_values()
    1.69 +    defaults = IterableValues(default_values.__dict__)
    1.70 +    (opts, extraargs) = parser.parse_args(args = list(args),
    1.71 +                                          values = defaults)
    1.72      return opts, extraargs
    1.73  
    1.74  def execute(fn, *args):
    1.75 @@ -106,7 +142,7 @@ def _read_python_cfg(filename):
    1.76      return cfg
    1.77  
    1.78  def resolve_vm(server, session, vm_name):
    1.79 -    vm_uuid = execute(server.VM.get_by_label, session, vm_name)
    1.80 +    vm_uuid = execute(server.VM.get_by_name_label, session, vm_name)
    1.81      if not vm_uuid:
    1.82          return None
    1.83      else:
    1.84 @@ -204,7 +240,7 @@ def xapi_vm_start(*args):
    1.85          raise OptionError("No Domain name specified.")
    1.86      
    1.87      server, session = _connect()
    1.88 -    vm_uuid = execute(server.VM.get_by_label, session, args[0])
    1.89 +    vm_uuid = resolve_vm(server, session, args[0])
    1.90      print 'Starting VM %s (%s)' % (args[0], vm_uuid)
    1.91      success = execute(server.VM.start, session, vm_uuid)
    1.92      print 'Done.'
    1.93 @@ -233,9 +269,16 @@ def xapi_vbd_create(*args):
    1.94      if len(args) < 2:
    1.95          raise OptionError("Configuration file not specified")
    1.96  
    1.97 +    opts, args = parse_args('vbd-create', args)
    1.98      domname = args[0]
    1.99      filename = args[1]
   1.100 -    cfg = _read_python_cfg(filename)
   1.101 +
   1.102 +    cfg = {}
   1.103 +    for opt, val in opts:
   1.104 +        cfg[opt] = val
   1.105 +    cfg.update(_read_python_cfg(filename))
   1.106 +    
   1.107 +    
   1.108      print 'Creating VBD from %s ..' % filename
   1.109      server, session = _connect()
   1.110      vm_uuid = resolve_vm(server, session, domname)
   1.111 @@ -250,6 +293,7 @@ def xapi_vif_create(*args):
   1.112      domname = args[0]
   1.113      filename = args[1]
   1.114      cfg = _read_python_cfg(filename)
   1.115 +    
   1.116      print 'Creating VIF from %s ..' % filename
   1.117      server, session = _connect()
   1.118      vm_uuid = resolve_vm(server, session, domname)
   1.119 @@ -283,9 +327,17 @@ def xapi_sr_list(*args):
   1.120          print SR_LIST_FORMAT % sr_struct
   1.121  
   1.122  def xapi_vdi_create(*args):
   1.123 +    opts, args = parse_args('vdi-create', args)
   1.124 +
   1.125 +    if len(args) < 1:
   1.126 +        raise OptionError("Not enough arguments.")
   1.127 +
   1.128 +    cfg = {}
   1.129 +    for opt, val in opts:
   1.130 +        cfg[opt] = val
   1.131 +    cfg.update(_read_python_cfg(args[0]))
   1.132 +
   1.133      server, session = _connect()
   1.134 -    cfg = _read_python_cfg(args[0])
   1.135 -
   1.136      srs = execute(server.SR.get_all, session)
   1.137      sr = srs[0]
   1.138      cfg['SR'] = sr
   1.139 @@ -359,6 +411,8 @@ def main(args):
   1.140      except XenAPIError, e:
   1.141          print 'Error: %s' % str(e.args[1])
   1.142          sys.exit(2)
   1.143 +    except OptionError, e:
   1.144 +        print 'Error: %s' % e
   1.145  
   1.146      sys.exit(0)
   1.147      
     2.1 --- a/tools/python/xen/xend/XendAPI.py	Fri Oct 13 15:38:13 2006 +0100
     2.2 +++ b/tools/python/xen/xend/XendAPI.py	Fri Oct 13 17:17:45 2006 +0100
     2.3 @@ -1001,10 +1001,10 @@ class XendAPI:
     2.4          xendom = XendDomain.instance()
     2.5          vm = xendom.get_vm_with_dev_uuid('vbd', vbd_ref)
     2.6          if not vm:
     2.7 -            return xen_api_error(XEND_ERROR_VIF_INVALID)
     2.8 +            return xen_api_error(XEND_ERROR_VBD_INVALID)
     2.9          cfg = vm.get_dev_xenapi_config('vbd', vbd_ref)
    2.10          if not cfg:
    2.11 -            return xen_api_error(XEND_ERROR_VIF_INVALID)
    2.12 +            return xen_api_error(XEND_ERROR_VBD_INVALID)
    2.13          return xen_api_success(cfg)
    2.14      
    2.15      # class methods
    2.16 @@ -1016,7 +1016,7 @@ class XendAPI:
    2.17          dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
    2.18          vbd_ref = ''
    2.19          try:
    2.20 -            if vbd_struct.get('VDI', None):
    2.21 +            if not vbd_struct.get('VDI', None):
    2.22                  # this is a traditional VBD without VDI and SR 
    2.23                  vbd_ref = dom.create_vbd(vbd_struct)
    2.24              else:
    2.25 @@ -1024,8 +1024,10 @@ class XendAPI:
    2.26                  vdi_ref = vbd_struct.get('VDI')
    2.27                  sr = XendNode.instance().get_sr()
    2.28                  vdi_image = sr.xen_api_get_by_uuid(vdi_ref)
    2.29 -                vdi_image_path = vdi_image.image_path
    2.30 -                vbd_ref = dom.create_vbd_with_vdi(vbd_struct, vdi_image_path)
    2.31 +                if not vdi_image:
    2.32 +                    return xen_api_error(XEND_ERROR_VDI_INVALID)
    2.33 +                vdi_image = vdi_image.qcow_path
    2.34 +                vbd_ref = dom.create_vbd_with_vdi(vbd_struct, vdi_image)
    2.35          except XendError:
    2.36              return xen_api_todo()
    2.37  
     3.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Oct 13 15:38:13 2006 +0100
     3.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Oct 13 17:17:45 2006 +0100
     3.3 @@ -28,6 +28,7 @@ import logging
     3.4  import time
     3.5  import threading
     3.6  import re
     3.7 +import copy
     3.8  
     3.9  import xen.lowlevel.xc
    3.10  from xen.util import asserts
    3.11 @@ -1719,28 +1720,44 @@ class XendDomainInfo:
    3.12  
    3.13      def get_dev_config_by_uuid(self, dev_class, dev_uuid):
    3.14          """ Get's a device configuration either from XendConfig or
    3.15 -        from the DevController."""
    3.16 +        from the DevController.
    3.17 +
    3.18 +        @param dev_class: device class, either, 'vbd' or 'vif'
    3.19 +        @param dev_uuid: device UUID
    3.20 +
    3.21 +        @rtype: dictionary
    3.22 +        """
    3.23 +        dev_type_config = self.info['device'].get(dev_uuid)
    3.24 +
    3.25 +        # shortcut if the domain isn't started because
    3.26 +        # the devcontrollers will have no better information
    3.27 +        # than XendConfig.
    3.28          if self.state in (XEN_API_VM_POWER_STATE_HALTED,):
    3.29 -            dev = self.info['device'].get(dev_uuid)
    3.30 -            if dev:
    3.31 -                return dev[1].copy()
    3.32 +            if dev_type_config:
    3.33 +                return copy.deepcopy(dev_type_config[1])
    3.34              return None
    3.35 -        else:
    3.36 -            controller = self.getDeviceController(dev_class)
    3.37 -            if not controller:
    3.38 -                return None
    3.39 +
    3.40 +        # instead of using dev_class, we use the dev_type
    3.41 +        # that is from XendConfig.
    3.42 +        # This will accomdate 'tap' as well as 'vbd'
    3.43 +        dev_type = dev_type_config[0]
    3.44 +        
    3.45 +        controller = self.getDeviceController(dev_type)
    3.46 +        if not controller:
    3.47 +            return None
    3.48              
    3.49 -            all_configs = controller.getAllDeviceConfigurations()
    3.50 -            if not all_configs:
    3.51 -                return None
    3.52 +        all_configs = controller.getAllDeviceConfigurations()
    3.53 +        if not all_configs:
    3.54 +            return None
    3.55  
    3.56 -            for _devid, _devcfg in all_configs.items():
    3.57 -                if _devcfg.get('uuid') == dev_uuid:
    3.58 -                    devcfg = _devcfg.copy()
    3.59 -                    devcfg['id'] = _devid
    3.60 -                    return devcfg
    3.61 +        dev_config = copy.deepcopy(dev_type_config[1])
    3.62 +        for _devid, _devcfg in all_configs.items():
    3.63 +            if _devcfg.get('uuid') == dev_uuid:
    3.64 +                dev_config.update(_devcfg)
    3.65 +                dev_config['id'] = _devid
    3.66 +                return dev_config
    3.67  
    3.68 -        return None
    3.69 +        return dev_config
    3.70                      
    3.71      def get_dev_xenapi_config(self, dev_class, dev_uuid):
    3.72          config = self.get_dev_config_by_uuid(dev_class, dev_uuid)
    3.73 @@ -1770,10 +1787,11 @@ class XendDomainInfo:
    3.74              config['IO_bandwidth_incoming_kbs'] = 0.0
    3.75              config['IO_bandwidth_outgoing_kbs'] = 0.0
    3.76  
    3.77 -        if dev_class == 'vbd':
    3.78 +        if dev_class =='vbd':
    3.79              config['VDI'] = '' # TODO
    3.80              config['device'] = config.get('dev', '')
    3.81 -            config['driver'] = config.get('uname', '')
    3.82 +            config['driver'] = 'paravirtualised' # TODO
    3.83 +            config['image'] = config.get('uname', '')
    3.84              config['IO_bandwidth_incoming_kbs'] = 0.0
    3.85              config['IO_bandwidth_outgoing_kbs'] = 0.0
    3.86              if config['mode'] == 'r':
    3.87 @@ -1835,6 +1853,7 @@ class XendDomainInfo:
    3.88          @return: uuid of the device
    3.89          """
    3.90          xenapi_vbd['image'] = vdi_image_path
    3.91 +        log.debug('create_vbd_with_vdi: %s' % xenapi_vbd)
    3.92          dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
    3.93          if not dev_uuid:
    3.94              raise XendError('Failed to create device')