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@jp.fujitsu.com>
This commit is contained in:
Keir Fraser committed 2008-10-16 09:50:18 +01:00
1 parent 2a010416e0
commit 44a6b9e6d4
13 files changed
+942 -117

No files matched your search

+2 -17
View File
@@ -12,8 +12,8 @@ import re
import types
import struct
import time
from xen.util import utils
PROC_MNT_PATH = '/proc/mounts'
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)))
+26
View File
@@ -48,3 +48,29 @@ def daemonize(prog, args, stdin_tmpfile=None):
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
+109 -2
View File
@@ -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_block_scsiid_to_hctl(phyname, scsi_devices):
def vscsi_get_scsidevices():
""" get all scsi devices"""
SERCH_SCSI_PATH = "/sys/bus/scsi/devices"
devices = []
sysfs_mnt = utils.find_sysfs_mount()
for dirpath, dirnames, files in os.walk(SERCH_SCSI_PATH):
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
+18 -2
View File
@@ -42,6 +42,8 @@ from XendPIF import XendPIF
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'),
+165 -36
View File
@@ -26,6 +26,8 @@ from xen.xend import XendOptions
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,
@@ -1254,6 +1255,30 @@ class XendConfig(dict):
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:
opt, val = opt_val
@@ -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,28 +1745,52 @@ 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:]:
try:
opt, val = opt_val
+174
View File
@@ -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@jp.fujitsu.com>
#============================================================================
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())
+105 -5
View File
@@ -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.
@@ -3417,6 +3424,60 @@ class XendDomainInfo:
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):
if dev_uuid not in self.info['devices']:
@@ -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()])
+38 -1
View File
@@ -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 XendNetwork import *
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()
@@ -320,6 +341,15 @@ class XendNode:
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
def save(self):
# save state
host_record = {self.uuid: {'name_label':self.name,
@@ -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(
@@ -363,6 +394,12 @@ class XendNode:
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
+143
View File
@@ -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@jp.fujitsu.com>
#============================================================================
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
+9 -9
View File
@@ -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')
+5
View File
@@ -40,6 +40,7 @@
vif*,
vtpm*,
pci*,
vscsi*,
console*,
platform*,
vcpu_param*,
@@ -88,6 +89,10 @@
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>
+89 -45
View File
@@ -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] ])
p_scsi = args[1]
v_hctl = args[2]
scsi = parse_scsi_configuration(p_scsi, v_hctl, 'Initialising')
if len(args) == 4:
vscsi.append(['backend', args[3]])
if serverType == SERVER_XEN_API:
vscsi.append(['state', 'Initialising'])
vscsi.append(['devid', v_hctl[0]])
server.xend.domain.device_configure(dom, vscsi)
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] ])
v_hctl = args[1]
scsi = parse_scsi_configuration(None, v_hctl, 'Closing')
vscsi.append(['state', 'Closing'])
vscsi.append(['devid', v_hctl[0]])
server.xend.domain.device_configure(dom, vscsi)
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()
+59
View File
@@ -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)
@@ -563,6 +596,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
impl = getDOMImplementation()
@@ -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)
@@ -894,6 +936,23 @@ class sxp2xml:
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")
other_config.attributes["key"] = key
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.