mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
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:
1 parent
2a010416e0
commit
44a6b9e6d4
13 files changed
+942
-117
No files matched your search
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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()])
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||