[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Enhance XenAPI for pvSCSI
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1224147018 -3600 # Node ID 9404bcb6d32e2a3873289254a42b0dbf6663a41c # Parent 22c89412fc8c0b7d47b73b7d67f0ef88b07b935e Enhance XenAPI for pvSCSI Basically, I implemented XenAPI for pvSCSI according to the patch of XenAPI document which I sent before. However, I renamed the class name of virtual SCSI devices to "DSCSI". Signed-off-by: Masaki Kanno <kanno.masaki@xxxxxxxxxxxxxx> --- tools/python/xen/util/pci.py | 21 --- tools/python/xen/util/utils.py | 26 ++++ tools/python/xen/util/vscsi_util.py | 113 +++++++++++++++++ tools/python/xen/xend/XendAPI.py | 20 ++- tools/python/xen/xend/XendConfig.py | 201 ++++++++++++++++++++++++++------ tools/python/xen/xend/XendDSCSI.py | 174 +++++++++++++++++++++++++++ tools/python/xen/xend/XendDomainInfo.py | 110 ++++++++++++++++- tools/python/xen/xend/XendNode.py | 39 ++++++ tools/python/xen/xend/XendPSCSI.py | 143 ++++++++++++++++++++++ tools/python/xen/xend/server/vscsiif.py | 18 +- tools/python/xen/xm/create.dtd | 5 tools/python/xen/xm/main.py | 140 ++++++++++++++-------- tools/python/xen/xm/xenapi_create.py | 59 +++++++++ 13 files changed, 947 insertions(+), 122 deletions(-) diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/util/pci.py --- a/tools/python/xen/util/pci.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/util/pci.py Thu Oct 16 09:50:18 2008 +0100 @@ -12,8 +12,8 @@ import types import types import struct import time - -PROC_MNT_PATH = '/proc/mounts' +from xen.util import utils + PROC_PCI_PATH = '/proc/bus/pci/devices' PROC_PCI_NUM_RESOURCES = 7 @@ -97,9 +97,6 @@ MSIX_SIZE_MASK = 0x7ff # Global variable to store information from lspci lspci_info = None -# Global variable to store the sysfs mount point -sysfs_mnt_point = None - #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number PAGE_SIZE = resource.getpagesize() PAGE_SHIFT = 0 @@ -141,20 +138,8 @@ def parse_pci_name(pci_name_string): def find_sysfs_mnt(): - global sysfs_mnt_point - if not sysfs_mnt_point is None: - return sysfs_mnt_point - try: - mounts_file = open(PROC_MNT_PATH,'r') - - for line in mounts_file: - sline = line.split() - if len(sline)<3: - continue - if sline[2]=='sysfs': - sysfs_mnt_point= sline[1] - return sysfs_mnt_point + return utils.find_sysfs_mount() except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)'% (PROC_PCI_PATH, strerr, errno))) diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/util/utils.py --- a/tools/python/xen/util/utils.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/util/utils.py Thu Oct 16 09:50:18 2008 +0100 @@ -48,3 +48,29 @@ def daemonize(prog, args, stdin_tmpfile= os.waitpid(pid, 0) return daemon_pid +# Global variable to store the sysfs mount point +sysfs_mount_point = None + +PROC_MOUNTS_PATH = '/proc/mounts' + +def find_sysfs_mount(): + global sysfs_mount_point + + if not sysfs_mount_point is None: + return sysfs_mount_point + + try: + mounts_file = open(PROC_MOUNTS_PATH, 'r') + + for line in mounts_file: + sline = line.split() + if len(sline) < 3: + continue + if sline[2] == 'sysfs': + sysfs_mount_point= sline[1] + return sysfs_mount_point + except IOError, (errno, strerr): + raise + + return None + diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/util/vscsi_util.py --- a/tools/python/xen/util/vscsi_util.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/util/vscsi_util.py Thu Oct 16 09:50:18 2008 +0100 @@ -23,9 +23,18 @@ """Support for VSCSI Devices. """ import os +import os.path import sys import re import string +from xen.util import utils + +SYSFS_SCSI_PATH = "/bus/scsi/devices" +SYSFS_SCSI_DEV_VENDOR_PATH = '/vendor' +SYSFS_SCSI_DEV_MODEL_PATH = '/model' +SYSFS_SCSI_DEV_TYPEID_PATH = '/type' +SYSFS_SCSI_DEV_REVISION_PATH = '/rev' +SYSFS_SCSI_DEV_SCSILEVEL_PATH = '/scsi_level' def _vscsi_hctl_block(name, scsi_devices): """ block-device name is convert into hctl. (e.g., '/dev/sda', @@ -84,10 +93,10 @@ def vscsi_get_scsidevices(): def vscsi_get_scsidevices(): """ get all scsi devices""" - SERCH_SCSI_PATH = "/sys/bus/scsi/devices" devices = [] - - for dirpath, dirnames, files in os.walk(SERCH_SCSI_PATH): + sysfs_mnt = utils.find_sysfs_mount() + + for dirpath, dirnames, files in os.walk(sysfs_mnt + SYSFS_SCSI_PATH): for hctl in dirnames: paths = os.path.join(dirpath, hctl) block = "-" @@ -131,3 +140,101 @@ def vscsi_search_hctl_and_block(device): return (hctl, block) + +def get_scsi_vendor(pHCTL): + try: + sysfs_mnt = utils.find_sysfs_mount() + sysfs_scsi_dev_path = \ + os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL) + scsi_vendor = \ + os.popen('cat ' + sysfs_scsi_dev_path + \ + SYSFS_SCSI_DEV_VENDOR_PATH).read() + return scsi_vendor.splitlines()[0] + except: + return None + +def get_scsi_model(pHCTL): + try: + sysfs_mnt = utils.find_sysfs_mount() + sysfs_scsi_dev_path = \ + os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL) + scsi_model = \ + os.popen('cat ' + sysfs_scsi_dev_path + \ + SYSFS_SCSI_DEV_MODEL_PATH).read() + return scsi_model.splitlines()[0] + except: + return None + +def get_scsi_typeid(pHCTL): + try: + sysfs_mnt = utils.find_sysfs_mount() + sysfs_scsi_dev_path = \ + os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL) + scsi_typeid = \ + os.popen('cat ' + sysfs_scsi_dev_path + \ + SYSFS_SCSI_DEV_TYPEID_PATH).read() + return int(scsi_typeid.splitlines()[0]) + except: + return None + +def get_scsi_revision(pHCTL): + try: + sysfs_mnt = utils.find_sysfs_mount() + sysfs_scsi_dev_path = \ + os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL) + scsi_revision = \ + os.popen('cat ' + sysfs_scsi_dev_path + \ + SYSFS_SCSI_DEV_REVISION_PATH).read() + return scsi_revision.splitlines()[0] + except: + return None + +def get_scsi_scsilevel(pHCTL): + try: + sysfs_mnt = utils.find_sysfs_mount() + sysfs_scsi_dev_path = \ + os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL) + scsi_scsilevel = \ + os.popen('cat ' + sysfs_scsi_dev_path + \ + SYSFS_SCSI_DEV_SCSILEVEL_PATH).read() + return int(scsi_scsilevel.splitlines()[0]) + except: + return None + +def get_all_scsi_devices(): + + scsi_devs = [] + + for scsi_info in vscsi_get_scsidevices(): + scsi_dev = { + 'physical_HCTL': scsi_info[0], + 'dev_name': None, + 'sg_name': scsi_info[2], + 'scsi_id': None + } + if scsi_info[1] != '-': + scsi_dev['dev_name'] = scsi_info[1] + if scsi_info[3] != '-': + scsi_dev['scsi_id'] = scsi_info[3] + + scsi_dev['vendor_name'] = \ + get_scsi_vendor(scsi_dev['physical_HCTL']) + scsi_dev['model'] = \ + get_scsi_model(scsi_dev['physical_HCTL']) + scsi_dev['type_id'] = \ + get_scsi_typeid(scsi_dev['physical_HCTL']) + scsi_dev['revision'] = \ + get_scsi_revision(scsi_dev['physical_HCTL']) + scsi_dev['scsi_level'] = \ + get_scsi_scsilevel(scsi_dev['physical_HCTL']) + + try: + lsscsi_info = os.popen('lsscsi ' + scsi_dev['physical_HCTL']).read().split() + scsi_dev['type'] = lsscsi_info[1] + except: + scsi_dev['type'] = None + + scsi_devs.append(scsi_dev) + + return scsi_devs + diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xend/XendAPI.py --- a/tools/python/xen/xend/XendAPI.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xend/XendAPI.py Thu Oct 16 09:50:18 2008 +0100 @@ -42,6 +42,8 @@ from XendPBD import XendPBD from XendPBD import XendPBD from XendPPCI import XendPPCI from XendDPCI import XendDPCI +from XendPSCSI import XendPSCSI +from XendDSCSI import XendDSCSI from XendXSPolicy import XendXSPolicy, XendACMPolicy from XendAPIConstants import * @@ -480,7 +482,9 @@ classes = { 'PBD' : valid_object("PBD"), 'PIF_metrics' : valid_object("PIF_metrics"), 'PPCI' : valid_object("PPCI"), - 'DPCI' : valid_object("DPCI") + 'DPCI' : valid_object("DPCI"), + 'PSCSI' : valid_object("PSCSI"), + 'DSCSI' : valid_object("DSCSI") } autoplug_classes = { @@ -491,6 +495,8 @@ autoplug_classes = { 'PIF_metrics' : XendPIFMetrics, 'PPCI' : XendPPCI, 'DPCI' : XendDPCI, + 'PSCSI' : XendPSCSI, + 'DSCSI' : XendDSCSI, 'XSPolicy' : XendXSPolicy, 'ACMPolicy' : XendACMPolicy, } @@ -881,6 +887,7 @@ class XendAPI(object): 'PBDs', 'PIFs', 'PPCIs', + 'PSCSIs', 'host_CPUs', 'cpu_configuration', 'metrics', @@ -961,6 +968,8 @@ class XendAPI(object): return xen_api_success(XendNode.instance().get_PIF_refs()) def host_get_PPCIs(self, session, ref): return xen_api_success(XendNode.instance().get_PPCI_refs()) + def host_get_PSCSIs(self, session, ref): + return xen_api_success(XendNode.instance().get_PSCSI_refs()) def host_get_host_CPUs(self, session, host_ref): return xen_api_success(XendNode.instance().get_host_cpu_refs()) def host_get_metrics(self, _, ref): @@ -1037,7 +1046,8 @@ class XendAPI(object): 'logging': {}, 'PIFs': XendPIF.get_all(), 'PBDs': XendPBD.get_all(), - 'PPCIs': XendPPCI.get_all()} + 'PPCIs': XendPPCI.get_all(), + 'PSCSIs': XendPSCSI.get_all()} return xen_api_success(record) # class methods @@ -1158,6 +1168,7 @@ class XendAPI(object): 'VBDs', 'VTPMs', 'DPCIs', + 'DSCSIs', 'tools_version', 'domid', 'is_control_domain', @@ -1304,6 +1315,10 @@ class XendAPI(object): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_dpcis()) + def VM_get_DSCSIs(self, session, vm_ref): + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + return xen_api_success(dom.get_dscsis()) + def VM_get_tools_version(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return dom.get_tools_version() @@ -1684,6 +1699,7 @@ class XendAPI(object): 'VBDs': xeninfo.get_vbds(), 'VTPMs': xeninfo.get_vtpms(), 'DPCIs': xeninfo.get_dpcis(), + 'DSCSIs': xeninfo.get_dscsis(), 'PV_bootloader': xeninfo.info.get('PV_bootloader'), 'PV_kernel': xeninfo.info.get('PV_kernel'), 'PV_ramdisk': xeninfo.info.get('PV_ramdisk'), diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xend/XendConfig.py Thu Oct 16 09:50:18 2008 +0100 @@ -26,6 +26,8 @@ from xen.xend import XendAPIStore from xen.xend import XendAPIStore from xen.xend.XendPPCI import XendPPCI from xen.xend.XendDPCI import XendDPCI +from xen.xend.XendPSCSI import XendPSCSI +from xen.xend.XendDSCSI import XendDSCSI from xen.xend.XendError import VmError from xen.xend.XendDevices import XendDevices from xen.xend.PrettyPrint import prettyprintstring @@ -782,8 +784,8 @@ class XendConfig(dict): log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg)) # _parse_sxp() below will call device_add() and construct devices. - # Some devices (currently only pci) may require VM's uuid, so - # setup self['uuid'] beforehand. + # Some devices may require VM's uuid, so setup self['uuid'] + # beforehand. self['uuid'] = sxp.child_value(sxp_cfg, 'uuid', uuid.createString()) cfg = self._parse_sxp(sxp_cfg) @@ -1222,29 +1224,28 @@ class XendConfig(dict): dev_type = sxp.name(config) dev_info = {} - if dev_type == 'pci' or dev_type == 'vscsi': + if dev_type == 'pci': pci_devs_uuid = sxp.child_value(config, 'uuid', uuid.createString()) pci_dict = self.pci_convert_sxp_to_dict(config) pci_devs = pci_dict['devs'] - if dev_type != 'vscsi': - # create XenAPI DPCI objects. - for pci_dev in pci_devs: - dpci_uuid = pci_dev.get('uuid') - ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'], - pci_dev['bus'], - pci_dev['slot'], - pci_dev['func']) - if ppci_uuid is None: - continue - dpci_record = { - 'VM': self['uuid'], - 'PPCI': ppci_uuid, - 'hotplug_slot': pci_dev.get('vslot', 0) - } - XendDPCI(dpci_uuid, dpci_record) + # create XenAPI DPCI objects. + for pci_dev in pci_devs: + dpci_uuid = pci_dev.get('uuid') + ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'], + pci_dev['bus'], + pci_dev['slot'], + pci_dev['func']) + if ppci_uuid is None: + continue + dpci_record = { + 'VM': self['uuid'], + 'PPCI': ppci_uuid, + 'hotplug_slot': pci_dev.get('vslot', 0) + } + XendDPCI(dpci_uuid, dpci_record) target['devices'][pci_devs_uuid] = (dev_type, {'devs': pci_devs, @@ -1253,6 +1254,30 @@ class XendConfig(dict): log.debug("XendConfig: reading device: %s" % pci_devs) return pci_devs_uuid + + if dev_type == 'vscsi': + vscsi_devs_uuid = sxp.child_value(config, 'uuid', + uuid.createString()) + vscsi_dict = self.vscsi_convert_sxp_to_dict(config) + vscsi_devs = vscsi_dict['devs'] + + # create XenAPI DSCSI objects. + for vscsi_dev in vscsi_devs: + dscsi_uuid = vscsi_dev.get('uuid') + pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev']) + if pscsi_uuid is None: + continue + dscsi_record = { + 'VM': self['uuid'], + 'PSCSI': pscsi_uuid, + 'virtual_HCTL': vscsi_dev.get('v-dev') + } + XendDSCSI(dscsi_uuid, dscsi_record) + + target['devices'][vscsi_devs_uuid] = \ + (dev_type, {'devs': vscsi_devs, 'uuid': vscsi_devs_uuid} ) + log.debug("XendConfig: reading device: %s" % vscsi_devs) + return vscsi_devs_uuid for opt_val in config[1:]: try: @@ -1559,6 +1584,86 @@ class XendConfig(dict): return dev_config + def vscsi_convert_sxp_to_dict(self, dev_sxp): + """Convert vscsi device sxp to dict + @param dev_sxp: device configuration + @type dev_sxp: SXP object (parsed config) + @return: dev_config + @rtype: dictionary + """ + # Parsing the device SXP's. In most cases, the SXP looks + # like this: + # + # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]] + # + # However, for SCSI devices it looks like this: + # + # [device, + # [vscsi, + # [dev, + # [devid, 0], [p-devname, sdb], [p-dev, 1:0:0:1], + # [v-dev, 0:0:0:0], [state, Initialising] + # ], + # [dev, + # [devid, 0], [p-devname, sdc], [p-dev, 1:0:0:2], + # [v-dev, 0:0:0:1], [satet, Initialising] + # ] + # ], + # [vscsi, + # [dev, + # [devid, 1], [p-devname, sdg], [p-dev, 2:0:0:0], + # [v-dev, 1:0:0:0], [state, Initialising] + # ], + # [dev, + # [devid, 1], [p-devname, sdh], [p-dev, 2:0:0:1], + # [v-dev, 1:0:0:1], [satet, Initialising] + # ] + # ] + # ] + # + # It seems the reasoning for this difference is because + # vscsiif.py needs all the SCSI device configurations with + # same host number at the same time when creating the devices. + + # For SCSI device hotplug support, the SXP of SCSI devices is + # extendend like this: + # + # [device, + # [vscsi, + # [dev, + # [devid, 0], [p-devname, sdd], [p-dev, 1:0:0:3], + # [v-dev, 0:0:0:2], [state, Initialising] + # ] + # ] + # ] + # + # state 'Initialising' indicates that the device is being attached, + # while state 'Closing' indicates that the device is being detached. + # + # The Dict looks like this: + # + # { devs: [ {devid: 0, p-devname: sdd, p-dev: 1:0:0:3, + # v-dev: 0:0:0:2, state: Initialising} ] } + + dev_config = {} + + vscsi_devs = [] + for vscsi_dev in sxp.children(dev_sxp, 'dev'): + vscsi_dev_info = {} + for opt_val in vscsi_dev[1:]: + try: + opt, val = opt_val + vscsi_dev_info[opt] = val + except TypeError: + pass + # append uuid for each vscsi device. + vscsi_uuid = vscsi_dev_info.get('uuid', uuid.createString()) + vscsi_dev_info['uuid'] = vscsi_uuid + vscsi_devs.append(vscsi_dev_info) + dev_config['devs'] = vscsi_devs + + return dev_config + def console_add(self, protocol, location, other_config = {}): dev_uuid = uuid.createString() if protocol == 'vt100': @@ -1632,7 +1737,7 @@ class XendConfig(dict): dev_type, dev_info = self['devices'][dev_uuid] - if dev_type == 'pci' or dev_type == 'vscsi': # Special case for pci + if dev_type == 'pci': # Special case for pci pci_dict = self.pci_convert_sxp_to_dict(config) pci_devs = pci_dict['devs'] @@ -1640,26 +1745,50 @@ class XendConfig(dict): for dpci_uuid in XendDPCI.get_by_VM(self['uuid']): XendAPIStore.deregister(dpci_uuid, "DPCI") - if dev_type != 'vscsi': - # create XenAPI DPCI objects. - for pci_dev in pci_devs: - dpci_uuid = pci_dev.get('uuid') - ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'], - pci_dev['bus'], - pci_dev['slot'], - pci_dev['func']) - if ppci_uuid is None: - continue - dpci_record = { - 'VM': self['uuid'], - 'PPCI': ppci_uuid, - 'hotplug_slot': pci_dev.get('vslot', 0) - } - XendDPCI(dpci_uuid, dpci_record) + # create XenAPI DPCI objects. + for pci_dev in pci_devs: + dpci_uuid = pci_dev.get('uuid') + ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'], + pci_dev['bus'], + pci_dev['slot'], + pci_dev['func']) + if ppci_uuid is None: + continue + dpci_record = { + 'VM': self['uuid'], + 'PPCI': ppci_uuid, + 'hotplug_slot': pci_dev.get('vslot', 0) + } + XendDPCI(dpci_uuid, dpci_record) self['devices'][dev_uuid] = (dev_type, {'devs': pci_devs, 'uuid': dev_uuid}) + return True + + if dev_type == 'vscsi': # Special case for vscsi + vscsi_dict = self.vscsi_convert_sxp_to_dict(config) + vscsi_devs = vscsi_dict['devs'] + + # destroy existing XenAPI DSCSI objects + for dscsi_uuid in XendDSCSI.get_by_VM(self['uuid']): + XendAPIStore.deregister(dscsi_uuid, "DSCSI") + + # create XenAPI DSCSI objects. + for vscsi_dev in vscsi_devs: + dscsi_uuid = vscsi_dev.get('uuid') + pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev']) + if pscsi_uuid is None: + continue + dscsi_record = { + 'VM': self['uuid'], + 'PSCSI': pscsi_uuid, + 'virtual_HCTL': vscsi_dev.get('v-dev') + } + XendDSCSI(dscsi_uuid, dscsi_record) + + self['devices'][dev_uuid] = \ + (dev_type, {'devs': vscsi_devs, 'uuid': dev_uuid} ) return True for opt_val in config[1:]: diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xend/XendDSCSI.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xend/XendDSCSI.py Thu Oct 16 09:50:18 2008 +0100 @@ -0,0 +1,174 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright FUJITSU LIMITED 2008 +# Masaki Kanno <kanno.masaki@xxxxxxxxxxxxxx> +#============================================================================ + +from xen.xend.XendBase import XendBase +from xen.xend.XendPSCSI import XendPSCSI +from xen.xend import XendAPIStore +from xen.xend import sxp +from xen.xend import uuid as genuuid + +import XendDomain, XendNode + +from XendError import * +from XendTask import XendTask +from XendLogging import log + +class XendDSCSI(XendBase): + """Representation of a half-virtualized SCSI device.""" + + def getClass(self): + return "DSCSI" + + def getAttrRO(self): + attrRO = ['VM', + 'PSCSI', + 'virtual_host', + 'virtual_channel', + 'virtual_target', + 'virtual_lun', + 'virtual_HCTL', + 'runtime_properties'] + return XendBase.getAttrRO() + attrRO + + def getAttrRW(self): + attrRW = [] + return XendBase.getAttrRW() + attrRW + + def getAttrInst(self): + attrInst = ['VM', + 'PSCSI', + 'virtual_HCTL'] + return XendBase.getAttrInst() + attrInst + + def getMethods(self): + methods = ['destroy'] + return XendBase.getMethods() + methods + + def getFuncs(self): + funcs = ['create'] + return XendBase.getFuncs() + funcs + + getClass = classmethod(getClass) + getAttrRO = classmethod(getAttrRO) + getAttrRW = classmethod(getAttrRW) + getAttrInst = classmethod(getAttrInst) + getMethods = classmethod(getMethods) + getFuncs = classmethod(getFuncs) + + def create(self, dscsi_struct): + + # Check if VM is valid + xendom = XendDomain.instance() + if not xendom.is_valid_vm(dscsi_struct['VM']): + raise InvalidHandleError('VM', dscsi_struct['VM']) + dom = xendom.get_vm_by_uuid(dscsi_struct['VM']) + + # Check if PSCSI is valid + xennode = XendNode.instance() + pscsi_uuid = xennode.get_pscsi_by_uuid(dscsi_struct['PSCSI']) + if not pscsi_uuid: + raise InvalidHandleError('PSCSI', dscsi_struct['PSCSI']) + + # Assign PSCSI to VM + try: + dscsi_ref = XendTask.log_progress(0, 100, \ + dom.create_dscsi, \ + dscsi_struct) + except XendError, e: + log.exception("Error in create_dscsi") + raise + + return dscsi_ref + + create = classmethod(create) + + def get_by_VM(cls, VM_ref): + result = [] + for dscsi in XendAPIStore.get_all("DSCSI"): + if dscsi.get_VM() == VM_ref: + result.append(dscsi.get_uuid()) + return result + + get_by_VM = classmethod(get_by_VM) + + def __init__(self, uuid, record): + XendBase.__init__(self, uuid, record) + v_hctl = self.virtual_HCTL.split(':') + self.virtual_host = int(v_hctl[0]) + self.virtual_channel = int(v_hctl[1]) + self.virtual_target = int(v_hctl[2]) + self.virtual_lun = int(v_hctl[3]) + + def get_VM(self): + return self.VM + + def get_PSCSI(self): + return self.PSCSI + + def get_virtual_host(self): + return self.virtual_host + + def get_virtual_channel(self): + return self.virtual_channel + + def get_virtual_target(self): + return self.virtual_target + + def get_virtual_lun(self): + return self.virtual_lun + + def get_virtual_HCTL(self): + return self.virtual_HCTL + + def get_runtime_properties(self): + xendom = XendDomain.instance() + dominfo = xendom.get_vm_by_uuid(self.VM) + + try: + device_dict = {} + for device_sxp in dominfo.getDeviceSxprs('vscsi'): + target_dev = None + for dev in device_sxp[1][0][1]: + vdev = sxp.child_value(dev, 'v-dev') + if vdev == self.virtual_HCTL: + target_dev = dev + break + if target_dev is None: + continue + + dev_dict = {} + for info in target_dev[1:]: + dev_dict[info[0]] = info[1] + device_dict['dev'] = dev_dict + for info in device_sxp[1][1:]: + device_dict[info[0]] = info[1] + + return device_dict + except Exception, exn: + log.exception(exn) + return {} + + def destroy(self): + xendom = XendDomain.instance() + dom = xendom.get_vm_by_uuid(self.get_VM()) + if not dom: + raise InvalidHandleError("VM", self.get_VM()) + XendTask.log_progress(0, 100, \ + dom.destroy_dscsi, \ + self.get_uuid()) + diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xend/XendDomainInfo.py Thu Oct 16 09:50:18 2008 +0100 @@ -55,9 +55,11 @@ from xen.xend.XendAPIConstants import * from xen.xend.XendVMMetrics import XendVMMetrics +from xen.xend import XendAPIStore from xen.xend.XendPPCI import XendPPCI from xen.xend.XendDPCI import XendDPCI -from xen.xend import XendAPIStore +from xen.xend.XendPSCSI import XendPSCSI +from xen.xend.XendDSCSI import XendDSCSI MIGRATE_TIMEOUT = 30.0 BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp' @@ -663,6 +665,9 @@ class XendDomainInfo: if dev_type == 'pci': for dev in dev_config_dict['devs']: XendAPIStore.deregister(dev['uuid'], 'DPCI') + if dev_type == 'vscsi': + for dev in dev_config_dict['devs']: + XendAPIStore.deregister(dev['uuid'], 'DSCSI') elif dev_type == 'tap': self.info['vbd_refs'].remove(dev_uuid) else: @@ -786,12 +791,11 @@ class XendDomainInfo: if dev_class != 'vscsi': return False - dev_config = self.info.pci_convert_sxp_to_dict(dev_sxp) + dev_config = self.info.vscsi_convert_sxp_to_dict(dev_sxp) dev = dev_config['devs'][0] - req_devid = sxp.child_value(dev_sxp, 'devid') - req_devid = int(req_devid) + req_devid = int(dev['devid']) existing_dev_info = self._getDeviceInfo_vscsi(req_devid, dev['v-dev']) - state = sxp.child_value(dev_sxp, 'state') + state = dev['state'] if state == 'Initialising': # new create @@ -3237,6 +3241,9 @@ class XendDomainInfo: def get_dpcis(self): return XendDPCI.get_by_VM(self.info.get('uuid')) + def get_dscsis(self): + return XendDSCSI.get_by_VM(self.info.get('uuid')) + def create_vbd(self, xenapi_vbd, vdi_image_path): """Create a VBD using a VDI from XendStorageRepository. @@ -3416,6 +3423,60 @@ class XendDomainInfo: raise XendError('Failed to create device') return dpci_uuid + + def create_dscsi(self, xenapi_dscsi): + """Create scsi device from the passed struct in Xen API format. + + @param xenapi_dscsi: DSCSI struct from Xen API + @rtype: string + @return: UUID + """ + + dscsi_uuid = uuid.createString() + + # Convert xenapi to sxp + pscsi = XendAPIStore.get(xenapi_dscsi.get('PSCSI'), 'PSCSI') + devid = int(xenapi_dscsi.get('virtual_HCTL').split(':')[0]) + target_vscsi_sxp = \ + ['vscsi', + ['dev', + ['devid', devid], + ['p-devname', pscsi.get_dev_name()], + ['p-dev', pscsi.get_physical_HCTL()], + ['v-dev', xenapi_dscsi.get('virtual_HCTL')], + ['state', 'Initialising'], + ['uuid', dscsi_uuid] + ] + ] + + if self._stateGet() != XEN_API_VM_POWER_STATE_RUNNING: + + cur_vscsi_sxp = self._getDeviceInfo_vscsi(devid, None) + + if cur_vscsi_sxp is None: + dev_uuid = self.info.device_add('vscsi', cfg_sxp = target_vscsi_sxp) + if not dev_uuid: + raise XendError('Failed to create device') + + else: + new_vscsi_sxp = ['vscsi'] + for existing_dev in sxp.children(cur_vscsi_sxp, 'dev'): + new_vscsi_sxp.append(existing_dev) + new_vscsi_sxp.append(sxp.child0(target_vscsi_sxp, 'dev')) + + dev_uuid = sxp.child_value(cur_vscsi_sxp, 'uuid') + self.info.device_update(dev_uuid, new_vscsi_sxp) + + xen.xend.XendDomain.instance().managed_config_save(self) + + else: + try: + self.device_configure(target_vscsi_sxp) + + except Exception, exn: + raise XendError('Failed to create device') + + return dscsi_uuid def destroy_device_by_uuid(self, dev_type, dev_uuid): @@ -3484,6 +3545,41 @@ class XendDomainInfo: except Exception, exn: raise XendError('Failed to destroy device') + def destroy_dscsi(self, dev_uuid): + dscsi = XendAPIStore.get(dev_uuid, 'DSCSI') + devid = dscsi.get_virtual_host() + vHCTL = dscsi.get_virtual_HCTL() + cur_vscsi_sxp = self._getDeviceInfo_vscsi(devid, None) + dev_uuid = sxp.child_value(cur_vscsi_sxp, 'uuid') + + target_dev = None + new_vscsi_sxp = ['vscsi'] + for dev in sxp.children(cur_vscsi_sxp, 'dev'): + if vHCTL == sxp.child_value(dev, 'v-dev'): + target_dev = dev + else: + new_vscsi_sxp.append(dev) + + if target_dev is None: + raise XendError('Failed to destroy device') + + target_dev.append(['state', 'Closing']) + target_vscsi_sxp = ['vscsi', target_dev] + + if self._stateGet() != XEN_API_VM_POWER_STATE_RUNNING: + + self.info.device_update(dev_uuid, new_vscsi_sxp) + if len(sxp.children(new_vscsi_sxp, 'dev')) == 0: + del self.info['devices'][dev_uuid] + xen.xend.XendDomain.instance().managed_config_save(self) + + else: + try: + self.device_configure(target_vscsi_sxp) + + except Exception, exn: + raise XendError('Failed to destroy device') + def destroy_xapi_instances(self): """Destroy Xen-API instances stored in XendAPIStore. """ @@ -3508,6 +3604,10 @@ class XendDomainInfo: for dpci_uuid in XendDPCI.get_by_VM(self.info.get('uuid')): XendAPIStore.deregister(dpci_uuid, "DPCI") + # Destroy DSCSI instances. + for dscsi_uuid in XendDSCSI.get_by_VM(self.info.get('uuid')): + XendAPIStore.deregister(dscsi_uuid, "DSCSI") + def has_device(self, dev_class, dev_uuid): return (dev_uuid in self.info['%s_refs' % dev_class.lower()]) diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xend/XendNode.py --- a/tools/python/xen/xend/XendNode.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xend/XendNode.py Thu Oct 16 09:50:18 2008 +0100 @@ -22,6 +22,7 @@ import xen.lowlevel.xc from xen.util import Brctl from xen.util import pci as PciUtil +from xen.util import vscsi_util from xen.xend import XendAPIStore from xen.xend import osdep @@ -38,7 +39,8 @@ from XendStateStore import XendStateStor from XendStateStore import XendStateStore from XendMonitor import XendMonitor from XendPPCI import XendPPCI - +from XendPSCSI import XendPSCSI + class XendNode: """XendNode - Represents a Domain 0 Host.""" @@ -53,6 +55,7 @@ class XendNode: * network * Storage Repository * PPCI + * PSCSI """ self.xc = xen.lowlevel.xc.xc() @@ -269,6 +272,24 @@ class XendNode: XendPPCI(ppci_uuid, ppci_record) + # Initialise PSCSIs + saved_pscsis = self.state_store.load_state('pscsi') + saved_pscsi_table = {} + if saved_pscsis: + for pscsi_uuid, pscsi_record in saved_pscsis.items(): + try: + saved_pscsi_table[pscsi_record['scsi_id']] = pscsi_uuid + except KeyError: + pass + + for pscsi_record in vscsi_util.get_all_scsi_devices(): + if pscsi_record['scsi_id']: + # If saved uuid exists, use it. Otherwise create one. + pscsi_uuid = saved_pscsi_table.get(pscsi_record['scsi_id'], + uuid.createString()) + XendPSCSI(pscsi_uuid, pscsi_record) + + ## def network_destroy(self, net_uuid): ## del self.networks[net_uuid] ## self.save_networks() @@ -317,6 +338,15 @@ class XendNode: def get_ppci_by_uuid(self, ppci_uuid): if ppci_uuid in self.get_PPCI_refs(): return ppci_uuid + return None + + + def get_PSCSI_refs(self): + return XendPSCSI.get_all() + + def get_pscsi_by_uuid(self, pscsi_uuid): + if pscsi_uuid in self.get_PSCSI_refs(): + return pscsi_uuid return None @@ -333,6 +363,7 @@ class XendNode: self.save_PBDs() self.save_SRs() self.save_PPCIs() + self.save_PSCSIs() def save_PIFs(self): pif_records = dict([(pif_uuid, XendAPIStore.get( @@ -362,6 +393,12 @@ class XendNode: ppci_uuid, "PPCI").get_record()) for ppci_uuid in XendPPCI.get_all()]) self.state_store.save_state('ppci', ppci_records) + + def save_PSCSIs(self): + pscsi_records = dict([(pscsi_uuid, XendAPIStore.get( + pscsi_uuid, "PSCSI").get_record()) + for pscsi_uuid in XendPSCSI.get_all()]) + self.state_store.save_state('pscsi', pscsi_records) def shutdown(self): return 0 diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xend/XendPSCSI.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xend/XendPSCSI.py Thu Oct 16 09:50:18 2008 +0100 @@ -0,0 +1,143 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright FUJITSU LIMITED 2008 +# Masaki Kanno <kanno.masaki@xxxxxxxxxxxxxx> +#============================================================================ + +from xen.xend.XendBase import XendBase +from xen.xend.XendBase import XendAPIStore +from xen.xend import uuid as genuuid + +class XendPSCSI(XendBase): + """Representation of a physical SCSI device.""" + + def getClass(self): + return "PSCSI" + + def getAttrRO(self): + attrRO = ['host', + 'physical_host', + 'physical_channel', + 'physical_target', + 'physical_lun', + 'physical_HCTL', + 'vendor_name', + 'model', + 'type_id', + 'type', + 'dev_name', + 'sg_name', + 'revision', + 'scsi_id', + 'scsi_level'] + return XendBase.getAttrRO() + attrRO + + def getAttrRW(self): + attrRW = [] + return XendBase.getAttrRW() + attrRW + + def getAttrInst(self): + attrInst = [] + return XendBase.getAttrInst() + attrInst + + def getMethods(self): + methods = [] + return XendBase.getMethods() + methods + + def getFuncs(self): + funcs = [] + return XendBase.getFuncs() + funcs + + getClass = classmethod(getClass) + getAttrRO = classmethod(getAttrRO) + getAttrRW = classmethod(getAttrRW) + getAttrInst = classmethod(getAttrInst) + getMethods = classmethod(getMethods) + getFuncs = classmethod(getFuncs) + + def get_by_HCTL(self, physical_HCTL): + for pscsi in XendAPIStore.get_all("PSCSI"): + if pscsi.get_physical_HCTL() == physical_HCTL: + return pscsi.get_uuid() + return None + + get_by_HCTL = classmethod(get_by_HCTL) + + def __init__(self, uuid, record): + self.physical_HCTL = record['physical_HCTL'] + self.vendor_name = record['vendor_name'] + self.model = record['model'] + self.type_id = record['type_id'] + self.type = record['type'] + self.dev_name = record['dev_name'] + self.sg_name = record['sg_name'] + self.revision = record['revision'] + self.scsi_id = record['scsi_id'] + self.scsi_level = record['scsi_level'] + + p_hctl = self.physical_HCTL.split(':') + self.physical_host = int(p_hctl[0]) + self.physical_channel = int(p_hctl[1]) + self.physical_target = int(p_hctl[2]) + self.physical_lun = int(p_hctl[3]) + + XendBase.__init__(self, uuid, record) + + def get_host(self): + from xen.xend import XendNode + return XendNode.instance().get_uuid() + + def get_physical_host(self): + return self.physical_host + + def get_physical_channel(self): + return self.physical_channel + + def get_physical_target(self): + return self.physical_target + + def get_physical_lun(self): + return self.physical_lun + + def get_physical_HCTL(self): + return self.physical_HCTL + + def get_vendor_name(self): + return self.vendor_name + + def get_model(self): + return self.model + + def get_type_id(self): + return self.type_id + + def get_type(self): + return self.type + + def get_dev_name(self): + return self.dev_name + + def get_sg_name(self): + return self.sg_name + + def get_revision(self): + return self.revision + + def get_scsi_id(self): + return self.scsi_id + + def get_scsi_level(self): + return self.scsi_level + diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xend/server/vscsiif.py --- a/tools/python/xen/xend/server/vscsiif.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xend/server/vscsiif.py Thu Oct 16 09:50:18 2008 +0100 @@ -125,10 +125,10 @@ class VSCSIController(DevController): state = self.readBackend(devid, devpath + '/state') localdevid = self.readBackend(devid, devpath + '/devid') dev_dict = {'p-dev': pdev, - 'p-devname': pdevname, - 'v-dev': pdevname, - 'state': state, - 'devid': localdevid } + 'p-devname': pdevname, + 'v-dev': vdev, + 'state': state, + 'devid': localdevid } vscsi_devs.append(dev_dict) config['devs'] = vscsi_devs @@ -168,17 +168,17 @@ class VSCSIController(DevController): (devid, back, front) = self.getDeviceDetails(config) devid = int(devid) vscsi_config = config['devs'][0] - states = config.get('states', []) + state = vscsi_config.get('state', '') driver_state = self.readBackend(devid, 'state') if str(xenbusState['Connected']) != driver_state: raise VmError("Driver status is not connected") uuid = self.readBackend(devid, 'uuid') - if states[0] == 'Initialising': + if state == 'Initialising': back['uuid'] = uuid self.writeBackend(devid, back) - elif states[0] == 'Closing': + elif state == 'Closing': found = False devs = self.readBackendList(devid, "vscsi-devs") vscsipath = "vscsi-devs/" @@ -197,8 +197,8 @@ class VSCSIController(DevController): raise VmError("Device %s not connected" % vdev) else: - raise XendError('Error configuring device invalid state %s' - % state) + raise XendError("Error configuring device invalid " + "state '%s'" % state) self.writeBackend(devid, 'state', str(xenbusState['Reconfiguring'])) return self.readBackend(devid, 'uuid') diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xm/create.dtd --- a/tools/python/xen/xm/create.dtd Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xm/create.dtd Thu Oct 16 09:50:18 2008 +0100 @@ -40,6 +40,7 @@ vif*, vtpm*, pci*, + vscsi*, console*, platform*, vcpu_param*, @@ -87,6 +88,10 @@ slot CDATA #REQUIRED func CDATA #REQUIRED vslt CDATA #IMPLIED> + +<!ELEMENT vscsi EMPTY> +<!ATTLIST vscsi p-dev CDATA #REQUIRED + v-dev CDATA #REQUIRED> <!ELEMENT console (other_config*)> <!ATTLIST console protocol (vt100|rfb|rdp) #REQUIRED> diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xm/main.py --- a/tools/python/xen/xm/main.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xm/main.py Thu Oct 16 09:50:18 2008 +0100 @@ -2235,12 +2235,34 @@ def vscsi_convert_sxp_to_dict(dev_sxp): return dev_dict def xm_scsi_list(args): - xenapi_unsupported() (use_long, params) = arg_check_for_resource_list(args, "scsi-list") dom = params[0] - devs = server.xend.domain.getDeviceSxprs(dom, 'vscsi') + devs = [] + if serverType == SERVER_XEN_API: + + dscsi_refs = server.xenapi.VM.get_DSCSIs(get_single_vm(dom)) + dscsi_properties = \ + map(server.xenapi.DSCSI.get_runtime_properties, dscsi_refs) + dscsi_dict = {} + for dscsi_property in dscsi_properties: + devid = int(dscsi_property['dev']['devid']) + try: + dscsi_sxp = dscsi_dict[devid] + except: + dscsi_sxp = [['devs', []]] + for key, value in dscsi_property.items(): + if key != 'dev': + dscsi_sxp.append([key, value]) + dev_sxp = ['dev'] + dev_sxp.extend(map2sxp(dscsi_property['dev'])) + dscsi_sxp[0][1].append(dev_sxp) + dscsi_dict[devid] = dscsi_sxp + devs = map2sxp(dscsi_dict) + + else: + devs = server.xend.domain.getDeviceSxprs(dom, 'vscsi') if use_long: map(PrettyPrint.prettyprint, devs) @@ -2464,37 +2486,60 @@ def xm_pci_attach(args): else: server.xend.domain.device_configure(dom, pci) +def parse_scsi_configuration(p_scsi, v_hctl, state): + v = v_hctl.split(':') + if len(v) != 4: + raise OptionError("Invalid argument: %s" % v_hctl) + + if p_scsi is not None: + (p_hctl, block) = vscsi_util.vscsi_search_hctl_and_block(p_scsi) + if p_hctl == None: + raise OptionError("Cannot find device '%s'" % p_scsi) + else: + p_hctl = '' + block = '' + + scsi = ['vscsi'] + scsi.append(['dev', \ + ['state', state], \ + ['devid', int(v[0])], \ + ['p-dev', p_hctl], \ + ['p-devname', block], \ + ['v-dev', v_hctl] \ + ]) + + return scsi + def xm_scsi_attach(args): - xenapi_unsupported() - arg_check(args, 'scsi-attach', 3, 4) - p_devname = args[1] - v_dev = args[2] - - v_hctl = v_dev.split(':') - if len(v_hctl) != 4: - raise OptionError("Invalid argument: %s" % v_dev) - - (p_hctl, block) = vscsi_util.vscsi_search_hctl_and_block(p_devname) - - if p_hctl == None: - raise OptionError("Cannot find device \"%s\"" % p_devname) - dom = args[0] - vscsi = ['vscsi'] - vscsi.append(['dev', \ - ['state', 'Initialising'], \ - ['devid', v_hctl[0]], \ - ['p-dev', p_hctl], \ - ['p-devname', block], \ - ['v-dev', v_dev] ]) - - if len(args) == 4: - vscsi.append(['backend', args[3]]) - - vscsi.append(['state', 'Initialising']) - vscsi.append(['devid', v_hctl[0]]) - server.xend.domain.device_configure(dom, vscsi) + p_scsi = args[1] + v_hctl = args[2] + scsi = parse_scsi_configuration(p_scsi, v_hctl, 'Initialising') + + if serverType == SERVER_XEN_API: + + scsi_dev = sxp.children(scsi, 'dev')[0] + p_hctl = sxp.child_value(scsi_dev, 'p-dev') + target_ref = None + for pscsi_ref in server.xenapi.PSCSI.get_all(): + if p_hctl == server.xenapi.PSCSI.get_physical_HCTL(pscsi_ref): + target_ref = pscsi_ref + break + if target_ref is None: + raise OptionError("Cannot find device '%s'" % p_scsi) + + dscsi_record = { + "VM": get_single_vm(dom), + "PSCSI": target_ref, + "virtual_HCTL": v_hctl + } + server.xenapi.DSCSI.create(dscsi_record) + + else: + if len(args) == 4: + scsi.append(['backend', args[3]]) + server.xend.domain.device_configure(dom, scsi) def detach(args, deviceClass): rm_cfg = True @@ -2587,26 +2632,25 @@ def xm_pci_detach(args): server.xend.domain.device_configure(dom, pci) def xm_scsi_detach(args): - xenapi_unsupported() arg_check(args, 'scsi-detach', 2) - - v_dev = args[1] - v_hctl = v_dev.split(':') - if len(v_hctl) != 4: - raise OptionError("Invalid argument: %s" % v_dev) - dom = args[0] - vscsi = ['vscsi'] - vscsi.append(['dev', \ - ['state', 'Closing'], \ - ['devid', v_hctl[0]], \ - ['p-dev', ''], \ - ['p-devname', ''], \ - ['v-dev', v_dev] ]) - - vscsi.append(['state', 'Closing']) - vscsi.append(['devid', v_hctl[0]]) - server.xend.domain.device_configure(dom, vscsi) + v_hctl = args[1] + scsi = parse_scsi_configuration(None, v_hctl, 'Closing') + + if serverType == SERVER_XEN_API: + + target_ref = None + for dscsi_ref in server.xenapi.VM.get_DSCSIs(get_single_vm(dom)): + if v_hctl == server.xenapi.DSCSI.get_virtual_HCTL(dscsi_ref): + target_ref = dscsi_ref + break + if target_ref is None: + raise OptionError("Device %s not assigned" % v_hctl) + + server.xenapi.DSCSI.destroy(target_ref) + + else: + server.xend.domain.device_configure(dom, scsi) def xm_vnet_list(args): xenapi_unsupported() diff -r 22c89412fc8c -r 9404bcb6d32e tools/python/xen/xm/xenapi_create.py --- a/tools/python/xen/xm/xenapi_create.py Wed Oct 15 15:58:09 2008 +0100 +++ b/tools/python/xen/xm/xenapi_create.py Thu Oct 16 09:50:18 2008 +0100 @@ -375,6 +375,12 @@ class xenapi_create: self.create_pcis(vm_ref, pcis) + # Now create scsis + + scsis = vm.getElementsByTagName("vscsi") + + self.create_scsis(vm_ref, scsis) + return vm_ref except: server.xenapi.VM.destroy(vm_ref) @@ -532,6 +538,33 @@ class xenapi_create: return server.xenapi.DPCI.create(dpci_record) + def create_scsis(self, vm_ref, scsis): + log(DEBUG, "create_scsis") + return map(lambda scsi: self.create_scsi(vm_ref, scsi), scsis) + + def create_scsi(self, vm_ref, scsi): + log(DEBUG, "create_scsi") + + target_ref = None + for pscsi_ref in server.xenapi.PSCSI.get_all(): + if scsi.attributes["p-dev"].value == server.xenapi.PSCSI.get_physical_HCTL(pscsi_ref): + target_ref = pscsi_ref + break + if target_ref is None: + log(DEBUG, "create_scsi: scsi device not found") + return None + + dscsi_record = { + "VM": + vm_ref, + "PSCSI": + target_ref, + "virtual_HCTL": + scsi.attributes["v-dev"].value + } + + return server.xenapi.DSCSI.create(dscsi_record) + def get_child_by_name(exp, childname, default = None): try: return [child for child in sxp.children(exp) @@ -562,6 +595,9 @@ class sxp2xml: pcis_sxp = map(lambda x: x[1], [device for device in devices if device[1][0] == "pci"]) + + scsis_sxp = map(lambda x: x[1], [device for device in devices + if device[1][0] == "vscsi"]) # Create XML Document @@ -704,6 +740,12 @@ class sxp2xml: map(vm.appendChild, pcis) + # And now the scsis + + scsis = self.extract_scsis(scsis_sxp, document) + + map(vm.appendChild, scsis) + # Last but not least the consoles... consoles = self.extract_consoles(image, document) @@ -893,6 +935,23 @@ class sxp2xml: pcis.append(pci) return pcis + + def extract_scsis(self, scsis_sxp, document): + + scsis = [] + + for scsi_sxp in scsis_sxp: + for dev_sxp in sxp.children(scsi_sxp, "dev"): + scsi = document.createElement("vscsi") + + scsi.attributes["p-dev"] \ + = get_child_by_name(dev_sxp, "p-dev") + scsi.attributes["v-dev"] \ + = get_child_by_name(dev_sxp, "v-dev") + + scsis.append(scsi) + + return scsis def mk_other_config(self, key, value, document): other_config = document.createElement("other_config") _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |