mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
671 lines
26 KiB
Python
Executable File
671 lines
26 KiB
Python
Executable File
#!/usr/bin/python
|
|
# Copyright (C) 2006-2007 XenSource Ltd.
|
|
# Copyright (C) 2008-2009 Citrix Ltd.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU Lesser General Public License as published
|
|
# by the Free Software Foundation; version 2.1 only.
|
|
#
|
|
# This program 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.
|
|
#
|
|
# ISCSISR: ISCSI software initiator SR driver
|
|
#
|
|
|
|
import SR, VDI, SRCommand, util
|
|
import statvfs, time, LUNperVDI
|
|
import os, socket, sys, re, glob
|
|
import xml.dom.minidom
|
|
import shutil, xmlrpclib
|
|
import scsiutil, iscsilib
|
|
import xs_errors, errno
|
|
|
|
CAPABILITIES = ["SR_PROBE","VDI_CREATE","VDI_DELETE","VDI_ATTACH",
|
|
"VDI_DETACH", "VDI_INTRODUCE"]
|
|
|
|
CONFIGURATION = [ [ 'target', 'IP address or hostname of the iSCSI target (required)' ], \
|
|
[ 'targetIQN', 'The IQN of the target LUN group to be attached (required)' ], \
|
|
[ 'chapuser', 'The username to be used during CHAP authentication (optional)' ], \
|
|
[ 'chappassword', 'The password to be used during CHAP authentication (optional)' ], \
|
|
[ 'port', 'The network port number on which to query the target (optional)' ], \
|
|
[ 'multihomed', 'Enable multi-homing to this target, true or false (optional, defaults to same value as host.other_config:multipathing)' ] ]
|
|
|
|
DRIVER_INFO = {
|
|
'name': 'iSCSI',
|
|
'description': 'Base ISCSI SR driver, provides a LUN-per-VDI. Does not support creation of VDIs but accesses existing LUNs on a target.',
|
|
'vendor': 'Citrix Systems Inc',
|
|
'copyright': '(C) 2008 Citrix Systems Inc',
|
|
'driver_version': '1.0',
|
|
'required_api_version': '1.0',
|
|
'capabilities': CAPABILITIES,
|
|
'configuration': CONFIGURATION
|
|
}
|
|
|
|
INITIATORNAME_FILE = '/etc/iscsi/initiatorname.iscsi'
|
|
SECTOR_SHIFT = 9
|
|
DEFAULT_PORT = 3260
|
|
# 2^16 Max port number value
|
|
MAXPORT = 65535
|
|
MAX_TIMEOUT = 15
|
|
MAX_LUNID_TIMEOUT = 60
|
|
ISCSI_PROCNAME = "iscsi_tcp"
|
|
|
|
class ISCSISR(SR.SR):
|
|
"""ISCSI storage repository"""
|
|
def handles(type):
|
|
if type == "iscsi":
|
|
return True
|
|
return False
|
|
handles = staticmethod(handles)
|
|
|
|
def _synchroniseAddrList(self, addrlist):
|
|
if not self.multihomed:
|
|
return
|
|
change = False
|
|
if not self.dconf.has_key('multihomelist'):
|
|
change = True
|
|
self.mlist = []
|
|
mstr = ""
|
|
else:
|
|
self.mlist = self.dconf['multihomelist'].split(',')
|
|
mstr = self.dconf['multihomelist']
|
|
for val in addrlist:
|
|
if not val in self.mlist:
|
|
self.mlist.append(val)
|
|
if len(mstr):
|
|
mstr += ","
|
|
mstr += val
|
|
change = True
|
|
if change:
|
|
pbd = None
|
|
try:
|
|
pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
|
|
if pbd <> None:
|
|
device_config = self.session.xenapi.PBD.get_device_config(pbd)
|
|
device_config['multihomelist'] = mstr
|
|
self.session.xenapi.PBD.set_device_config(pbd, device_config)
|
|
except:
|
|
pass
|
|
|
|
|
|
@util.transformpasswords
|
|
def load(self, sr_uuid):
|
|
self.sr_vditype = 'phy'
|
|
self.discoverentry = 0
|
|
self.default_vdi_visibility = False
|
|
|
|
# Required parameters
|
|
if not self.dconf.has_key('target') or not self.dconf['target']:
|
|
raise xs_errors.XenError('ConfigTargetMissing')
|
|
|
|
# we are no longer putting hconf in the xml.
|
|
# Instead we pass a session and host ref and let the SM backend query XAPI itself
|
|
try:
|
|
if not self.dconf.has_key('localIQN'):
|
|
self.localIQN = self.session.xenapi.host.get_other_config(self.host_ref)['iscsi_iqn']
|
|
else:
|
|
self.localIQN = self.dconf['localIQN']
|
|
except:
|
|
raise xs_errors.XenError('ConfigISCSIIQNMissing')
|
|
|
|
# Check for empty string
|
|
if not self.localIQN:
|
|
raise xs_errors.XenError('ConfigISCSIIQNMissing')
|
|
|
|
try:
|
|
self.target = util._convertDNS(self.dconf['target'].split(',')[0])
|
|
except:
|
|
raise xs_errors.XenError('DNSError')
|
|
|
|
self.targetlist = self.target
|
|
if self.dconf.has_key('targetlist'):
|
|
self.targetlist = self.dconf['targetlist']
|
|
|
|
# Optional parameters
|
|
self.chapuser = ""
|
|
self.chappassword = ""
|
|
if self.dconf.has_key('chapuser') \
|
|
and (self.dconf.has_key('chappassword') or self.dconf.has_key('chappassword_secret')):
|
|
self.chapuser = self.dconf['chapuser']
|
|
if self.dconf.has_key('chappassword_secret'):
|
|
self.chappassword = util.get_secret(self.session, self.dconf['chappassword_secret'])
|
|
else:
|
|
self.chappassword = self.dconf['chappassword']
|
|
|
|
self.port = DEFAULT_PORT
|
|
if self.dconf.has_key('port') and self.dconf['port']:
|
|
try:
|
|
self.port = long(self.dconf['port'])
|
|
except:
|
|
raise xs_errors.XenError('ISCSIPort')
|
|
if self.port > MAXPORT or self.port < 1:
|
|
raise xs_errors.XenError('ISCSIPort')
|
|
|
|
# For backwards compatibility
|
|
if self.dconf.has_key('usediscoverynumber'):
|
|
self.discoverentry = self.dconf['usediscoverynumber']
|
|
|
|
self.multihomed = False
|
|
if self.dconf.has_key('multihomed'):
|
|
if self.dconf['multihomed'] == "true":
|
|
self.multihomed = True
|
|
elif self.mpath == 'true':
|
|
self.multihomed = True
|
|
|
|
if not self.dconf.has_key('targetIQN') or not self.dconf['targetIQN']:
|
|
self._scan_IQNs()
|
|
raise xs_errors.XenError('ConfigTargetIQNMissing')
|
|
|
|
self.targetIQN = self.dconf['targetIQN']
|
|
self.attached = False
|
|
try:
|
|
self.attached = iscsilib._checkTGT(self.targetIQN)
|
|
except:
|
|
pass
|
|
self._initPaths()
|
|
|
|
def _initPaths(self):
|
|
self._init_adapters()
|
|
# Generate a list of all possible paths
|
|
self.pathdict = {}
|
|
addrlist = []
|
|
rec = {}
|
|
key = "%s:%d" % (self.target,self.port)
|
|
rec['ipaddr'] = self.target
|
|
rec['port'] = self.port
|
|
rec['path'] = os.path.join("/dev/iscsi",self.targetIQN,\
|
|
key)
|
|
self.pathdict[key] = rec
|
|
util.SMlog("PATHDICT: key %s: %s" % (key,rec))
|
|
self.tgtidx = key
|
|
addrlist.append(key)
|
|
|
|
self.path = rec['path']
|
|
self.address = self.tgtidx
|
|
if not self.attached:
|
|
return
|
|
|
|
if self.multihomed:
|
|
map = iscsilib.get_node_records(targetIQN=self.targetIQN)
|
|
for i in range(0,len(map)):
|
|
(portal,tpgt,iqn) = map[i]
|
|
(ipaddr,port) = portal.split(',')[0].split(':')
|
|
if self.target != ipaddr:
|
|
key = "%s:%s" % (ipaddr,port)
|
|
rec = {}
|
|
rec['ipaddr'] = ipaddr
|
|
rec['port'] = long(port)
|
|
rec['path'] = os.path.join("/dev/iscsi",self.targetIQN,\
|
|
key)
|
|
self.pathdict[key] = rec
|
|
util.SMlog("PATHDICT: key %s: %s" % (key,rec))
|
|
addrlist.append(key)
|
|
|
|
# Try to detect an active path in order of priority
|
|
for key in self.pathdict:
|
|
if self.adapter.has_key(key):
|
|
self.tgtidx = key
|
|
self.path = self.pathdict[self.tgtidx]['path']
|
|
if os.path.exists(self.path):
|
|
util.SMlog("Path found: %s" % self.path)
|
|
break
|
|
self.address = self.tgtidx
|
|
self._synchroniseAddrList(addrlist)
|
|
|
|
def _init_adapters(self):
|
|
# Generate a list of active adapters
|
|
ids = scsiutil._genHostList(ISCSI_PROCNAME)
|
|
util.SMlog(ids)
|
|
self.adapter = {}
|
|
for host in ids:
|
|
try:
|
|
targetIQN = util.get_single_entry(glob.glob(\
|
|
'/sys/class/iscsi_host/host%s/device/session*/iscsi_session*/targetname' % host)[0])
|
|
if targetIQN != self.targetIQN:
|
|
continue
|
|
addr = util.get_single_entry(glob.glob(\
|
|
'/sys/class/iscsi_host/host%s/device/session*/connection*/iscsi_connection*/persistent_address' % host)[0])
|
|
port = util.get_single_entry(glob.glob(\
|
|
'/sys/class/iscsi_host/host%s/device/session*/connection*/iscsi_connection*/persistent_port' % host)[0])
|
|
entry = "%s:%s" % (addr,port)
|
|
self.adapter[entry] = host
|
|
except:
|
|
pass
|
|
self.devs = scsiutil.cacheSCSIidentifiers()
|
|
|
|
def attach(self, sr_uuid):
|
|
self._mpathHandle()
|
|
|
|
npaths=0
|
|
if not self.attached:
|
|
# Verify iSCSI target and port
|
|
if self.dconf.has_key('multihomelist') and not self.dconf.has_key('multiSession'):
|
|
targetlist = self.dconf['multihomelist'].split(',')
|
|
else:
|
|
targetlist = ['%s:%d' % (self.target,self.port)]
|
|
conn = False
|
|
for val in targetlist:
|
|
(target,port) = val.split(':')
|
|
try:
|
|
util._testHost(target, long(port), 'ISCSITarget')
|
|
self.target = target
|
|
self.port = long(port)
|
|
conn = True
|
|
break
|
|
except:
|
|
pass
|
|
if not conn:
|
|
raise xs_errors.XenError('ISCSITarget')
|
|
|
|
# Test and set the initiatorname file
|
|
iscsilib.ensure_daemon_running_ok(self.localIQN)
|
|
|
|
# Check to see if auto attach was set
|
|
if not iscsilib._checkTGT(self.targetIQN):
|
|
try:
|
|
map = iscsilib.discovery(self.target, self.port, self.chapuser, \
|
|
self.chappassword, targetIQN=self.targetIQN)
|
|
iqn = ''
|
|
if len(map) == 0:
|
|
self._scan_IQNs()
|
|
raise xs_errors.XenError('ISCSIDiscovery',
|
|
opterr='check target settings')
|
|
for i in range(0,len(map)):
|
|
(portal,tpgt,iqn) = map[i]
|
|
try:
|
|
(ipaddr,port) = portal.split(',')[0].split(':')
|
|
if not self.multihomed and ipaddr != self.target:
|
|
continue
|
|
util._testHost(ipaddr, long(port), 'ISCSITarget')
|
|
util.SMlog("Logging in to [%s:%s]" % (ipaddr,port))
|
|
iscsilib.login(portal, iqn, self.chapuser, self.chappassword)
|
|
npaths = npaths + 1
|
|
except:
|
|
pass
|
|
|
|
if not iscsilib._checkTGT(self.targetIQN):
|
|
raise xs_errors.XenError('ISCSIDevice', \
|
|
opterr='during login')
|
|
|
|
# Allow the devices to settle
|
|
time.sleep(5)
|
|
|
|
except util.CommandException, inst:
|
|
raise xs_errors.XenError('ISCSILogin', \
|
|
opterr='code is %d' % inst.code)
|
|
self.attached = True
|
|
self._initPaths()
|
|
util._incr_iscsiSR_refcount(self.targetIQN, sr_uuid)
|
|
IQNs = []
|
|
if self.dconf.has_key("multiSession"):
|
|
IQNs = ""
|
|
for iqn in self.dconf['multiSession'].split("|"):
|
|
if len(iqn): IQNs += iqn.split(',')[2]
|
|
else:
|
|
IQNs.append(self.targetIQN)
|
|
sessions = 0
|
|
paths = glob.glob(\
|
|
'/sys/class/iscsi_host/host*/device/session*/iscsi_session*/targetname')
|
|
for path in paths:
|
|
try:
|
|
if util.get_single_entry(path) in IQNs:
|
|
sessions += 1
|
|
util.SMlog("IQN match. Incrementing sessions to %d" % sessions)
|
|
except:
|
|
util.SMlog("Failed to read targetname path," \
|
|
+ "iscsi_sessions value may be incorrect")
|
|
|
|
try:
|
|
pbdref = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
|
|
if pbdref <> None:
|
|
other_conf = self.session.xenapi.PBD.get_other_config(pbdref)
|
|
other_conf['iscsi_sessions'] = str(sessions)
|
|
self.session.xenapi.PBD.set_other_config(pbdref, other_conf)
|
|
except:
|
|
pass
|
|
|
|
if self.mpath == 'true' and self.dconf.has_key('SCSIid'):
|
|
self.mpathmodule.refresh(self.dconf['SCSIid'],npaths)
|
|
|
|
|
|
def detach(self, sr_uuid):
|
|
keys = []
|
|
pbdref = None
|
|
try:
|
|
pbdref = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
|
|
except:
|
|
pass
|
|
if self.dconf.has_key('SCSIid'):
|
|
self.mpathmodule.reset(self.dconf['SCSIid'], True) # explicitly unmap
|
|
keys.append("mpath-" + self.dconf['SCSIid'])
|
|
|
|
# Remove iscsi_sessions and multipathed keys
|
|
if pbdref <> None:
|
|
if self.cmd == 'sr_detach':
|
|
keys += ["multipathed", "iscsi_sessions"]
|
|
for key in keys:
|
|
try:
|
|
self.session.xenapi.PBD.remove_from_other_config(pbdref, key)
|
|
except:
|
|
pass
|
|
|
|
if util._decr_iscsiSR_refcount(self.targetIQN, sr_uuid) != 0:
|
|
return
|
|
|
|
if self.direct and util._containsVDIinuse(self):
|
|
return
|
|
|
|
if iscsilib._checkTGT(self.targetIQN):
|
|
try:
|
|
iscsilib.logout(self.target, self.targetIQN, all=True)
|
|
except util.CommandException, inst:
|
|
raise xs_errors.XenError('ISCSIQueryDaemon', \
|
|
opterr='error is %d' % inst.code)
|
|
if iscsilib._checkTGT(self.targetIQN):
|
|
raise xs_errors.XenError('ISCSIQueryDaemon', \
|
|
opterr='Failed to logout from target')
|
|
|
|
self.attached = False
|
|
|
|
def create(self, sr_uuid, size):
|
|
# Check whether an SR already exists
|
|
SRs = self.session.xenapi.SR.get_all_records()
|
|
for sr in SRs:
|
|
record = SRs[sr]
|
|
sm_config = record["sm_config"]
|
|
if sm_config.has_key('targetIQN') and \
|
|
sm_config['targetIQN'] == self.targetIQN:
|
|
raise xs_errors.XenError('SRInUse')
|
|
self.attach(sr_uuid)
|
|
# Wait up to MAX_TIMEOUT for devices to appear
|
|
util.wait_for_path(self.path, MAX_TIMEOUT)
|
|
|
|
if self._loadvdis() > 0:
|
|
scanrecord = SR.ScanRecord(self)
|
|
scanrecord.synchronise()
|
|
try:
|
|
self.detach(sr_uuid)
|
|
except:
|
|
pass
|
|
self.sm_config = self.session.xenapi.SR.get_sm_config(self.sr_ref)
|
|
self.sm_config['disktype'] = 'Raw'
|
|
self.sm_config['datatype'] = 'ISCSI'
|
|
self.sm_config['target'] = self.target
|
|
self.sm_config['targetIQN'] = self.targetIQN
|
|
self.sm_config['multipathable'] = 'true'
|
|
self.session.xenapi.SR.set_sm_config(self.sr_ref, self.sm_config)
|
|
return
|
|
|
|
def delete(self, sr_uuid):
|
|
self.detach(sr_uuid)
|
|
return
|
|
|
|
def probe(self):
|
|
SRs = self.session.xenapi.SR.get_all_records()
|
|
Recs = {}
|
|
for sr in SRs:
|
|
record = SRs[sr]
|
|
sm_config = record["sm_config"]
|
|
if sm_config.has_key('targetIQN') and \
|
|
sm_config['targetIQN'] == self.targetIQN:
|
|
Recs[record["uuid"]] = sm_config
|
|
return self.srlist_toxml(Recs)
|
|
|
|
|
|
def scan(self, sr_uuid):
|
|
if not self.passthrough:
|
|
if not self.attached:
|
|
raise xs_errors.XenError('SRUnavailable')
|
|
self.refresh()
|
|
time.sleep(2) # it seems impossible to tell when a scan's finished
|
|
self._loadvdis()
|
|
self.physical_utilisation = self.physical_size
|
|
for uuid, vdi in self.vdis.iteritems():
|
|
if vdi.managed:
|
|
self.physical_utilisation += vdi.size
|
|
self.virtual_allocation = self.physical_utilisation
|
|
return super(ISCSISR, self).scan(sr_uuid)
|
|
|
|
def vdi(self, uuid):
|
|
return LUNperVDI.RAWVDI(self, uuid)
|
|
|
|
def _scan_IQNs(self):
|
|
# Verify iSCSI target and port
|
|
util._testHost(self.target, self.port, 'ISCSITarget')
|
|
|
|
# Test and set the initiatorname file
|
|
iscsilib.ensure_daemon_running_ok(self.localIQN)
|
|
|
|
map = iscsilib.discovery(self.target, self.port, self.chapuser, self.chappassword)
|
|
map.append(("%s:%d" % (self.targetlist,self.port),"0","*"))
|
|
self.print_entries(map)
|
|
|
|
def _attach_LUN_bylunid(self, lunid):
|
|
if not self.attached:
|
|
raise xs_errors.XenError('SRUnavailable')
|
|
connected = []
|
|
for val in self.adapter:
|
|
if not self.pathdict.has_key(val):
|
|
continue
|
|
rec = self.pathdict[val]
|
|
path = os.path.join(rec['path'],"LUN%s" % lunid)
|
|
util.SMlog("path: %s" % path)
|
|
realpath = os.path.realpath(path)
|
|
util.SMlog("realpath: %s" % realpath)
|
|
host = self.adapter[val]
|
|
if not self.devs.has_key(realpath):
|
|
l = [realpath, host, 0, 0, lunid]
|
|
scsiutil.scsi_dev_ctrl(l,"add")
|
|
if not util.wait_for_path(path, MAX_LUNID_TIMEOUT):
|
|
util.SMlog("Unable to detect LUN attached to host on path [%s]" % path)
|
|
continue
|
|
else:
|
|
# Verify that we are not seeing a stale LUN map
|
|
try:
|
|
real_SCSIid = scsiutil.getSCSIid(realpath)
|
|
cur_scsibuspath = glob.glob('/dev/disk/by-scsibus/*-%s:0:0:%s' % (host,lunid))
|
|
cur_SCSIid = os.path.basename(cur_scsibuspath[0]).split("-")[0]
|
|
assert(cur_SCSIid == real_SCSIid)
|
|
except:
|
|
scsiutil.rescan([host])
|
|
if not os.path.exists('/dev/disk/by-scsibus/%s-%s:0:0:%s' % \
|
|
(real_SCSIid,host,lunid)):
|
|
util.SMlog("Unable to detect LUN attached to host after bus re-probe")
|
|
continue
|
|
connected.append(path)
|
|
return connected
|
|
|
|
def _attach_LUN_byserialid(self, serialid):
|
|
if not self.attached:
|
|
raise xs_errors.XenError('SRUnavailable')
|
|
connected = []
|
|
for val in self.adapter:
|
|
if not self.pathdict.has_key(val):
|
|
continue
|
|
rec = self.pathdict[val]
|
|
path = os.path.join(rec['path'],"SERIAL-%s" % serialid)
|
|
realpath = os.path.realpath(path)
|
|
if not self.devs.has_key(realpath):
|
|
if not util.wait_for_path(path, 5):
|
|
util.SMlog("Unable to detect LUN attached to host on serial path [%s]" % path)
|
|
continue
|
|
connected.append(path)
|
|
return connected
|
|
|
|
def _detach_LUN_bylunid(self, lunid, SCSIid):
|
|
if not self.attached:
|
|
raise xs_errors.XenError('SRUnavailable')
|
|
if self.mpath == 'true' and len(SCSIid):
|
|
self.mpathmodule.reset(SCSIid, True)
|
|
util.remove_mpathcount_field(self.session, self.host_ref, self.sr_ref, SCSIid)
|
|
for val in self.adapter:
|
|
if not self.pathdict.has_key(val):
|
|
continue
|
|
rec = self.pathdict[val]
|
|
path = os.path.join(rec['path'],"LUN%s" % lunid)
|
|
realpath = os.path.realpath(path)
|
|
if self.devs.has_key(realpath):
|
|
util.SMlog("Found key: %s" % realpath)
|
|
scsiutil.scsi_dev_ctrl(self.devs[realpath], 'remove')
|
|
# Wait for device to disappear
|
|
if not util.wait_for_nopath(realpath, MAX_LUNID_TIMEOUT):
|
|
util.SMlog("Device has not disappeared after %d seconds" % \
|
|
MAX_LUNID_TIMEOUT)
|
|
else:
|
|
util.SMlog("Device [%s,%s] disappeared" % (realpath,path))
|
|
|
|
def _attach_LUN_bySCSIid(self, SCSIid):
|
|
if not self.attached:
|
|
raise xs_errors.XenError('SRUnavailable')
|
|
|
|
path = self.mpathmodule.path(SCSIid)
|
|
if not util.pathexists(path):
|
|
self.refresh()
|
|
if not util.wait_for_path(path, MAX_TIMEOUT):
|
|
util.SMlog("Unable to detect LUN attached to host [%s]" \
|
|
% path)
|
|
return False
|
|
return True
|
|
|
|
|
|
# This function queries the session for the attached LUNs
|
|
def _loadvdis(self):
|
|
count = 0
|
|
if not os.path.exists(self.path):
|
|
return 0
|
|
for file in filter(self.match_lun, util.listdir(self.path)):
|
|
vdi_path = os.path.join(self.path,file)
|
|
LUNid = file.replace("LUN","")
|
|
uuid = scsiutil.gen_uuid_from_string(scsiutil.getuniqueserial(vdi_path))
|
|
obj = self.vdi(uuid)
|
|
obj._query(vdi_path, LUNid)
|
|
self.vdis[uuid] = obj
|
|
self.physical_size += obj.size
|
|
count += 1
|
|
return count
|
|
|
|
def refresh(self):
|
|
for val in self.adapter:
|
|
util.SMlog("Rescanning host adapter %s" % self.adapter[val])
|
|
scsiutil.rescan([self.adapter[val]])
|
|
|
|
# Helper function for LUN-per-VDI VDI.introduce
|
|
def _getLUNbySMconfig(self, sm_config):
|
|
if not sm_config.has_key('LUNid'):
|
|
raise xs_errors.XenError('VDIUnavailable')
|
|
LUNid = long(sm_config['LUNid'])
|
|
if not len(self._attach_LUN_bylunid(LUNid)):
|
|
raise xs_errors.XenError('VDIUnavailable')
|
|
return os.path.join(self.path,"LUN%d" % LUNid)
|
|
|
|
def print_LUNs(self):
|
|
self.LUNs = {}
|
|
if os.path.exists(self.path):
|
|
for file in util.listdir(self.path):
|
|
if file.find("LUN") != -1 and file.find("_") == -1:
|
|
vdi_path = os.path.join(self.path,file)
|
|
LUNid = file.replace("LUN","")
|
|
obj = self.vdi(self.uuid)
|
|
obj._query(vdi_path, LUNid)
|
|
self.LUNs[obj.uuid] = obj
|
|
|
|
dom = xml.dom.minidom.Document()
|
|
element = dom.createElement("iscsi-target")
|
|
dom.appendChild(element)
|
|
for uuid in self.LUNs:
|
|
val = self.LUNs[uuid]
|
|
entry = dom.createElement('LUN')
|
|
element.appendChild(entry)
|
|
|
|
for attr in ('vendor', 'serial', 'LUNid', \
|
|
'size', 'SCSIid'):
|
|
try:
|
|
aval = getattr(val, attr)
|
|
except AttributeError:
|
|
continue
|
|
|
|
if aval:
|
|
subentry = dom.createElement(attr)
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(str(aval))
|
|
subentry.appendChild(textnode)
|
|
|
|
print >>sys.stderr,dom.toprettyxml()
|
|
|
|
def print_entries(self, map):
|
|
dom = xml.dom.minidom.Document()
|
|
element = dom.createElement("iscsi-target-iqns")
|
|
dom.appendChild(element)
|
|
count = 0
|
|
for address,tpgt,iqn in map:
|
|
entry = dom.createElement('TGT')
|
|
element.appendChild(entry)
|
|
subentry = dom.createElement('Index')
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(str(count))
|
|
subentry.appendChild(textnode)
|
|
|
|
try:
|
|
addr,port = address.split(":")
|
|
except:
|
|
addr = address
|
|
port = DEFAULT_PORT
|
|
subentry = dom.createElement('IPAddress')
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(str(addr))
|
|
subentry.appendChild(textnode)
|
|
|
|
if int(port) != DEFAULT_PORT:
|
|
subentry = dom.createElement('Port')
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(str(port))
|
|
subentry.appendChild(textnode)
|
|
|
|
subentry = dom.createElement('TargetIQN')
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(str(iqn))
|
|
subentry.appendChild(textnode)
|
|
count += 1
|
|
print >>sys.stderr,dom.toprettyxml()
|
|
|
|
def srlist_toxml(self, SRs):
|
|
dom = xml.dom.minidom.Document()
|
|
element = dom.createElement("SRlist")
|
|
dom.appendChild(element)
|
|
|
|
for val in SRs:
|
|
record = SRs[val]
|
|
entry = dom.createElement('SR')
|
|
element.appendChild(entry)
|
|
|
|
subentry = dom.createElement("UUID")
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(val)
|
|
subentry.appendChild(textnode)
|
|
|
|
subentry = dom.createElement("Target")
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(record['target'])
|
|
subentry.appendChild(textnode)
|
|
|
|
subentry = dom.createElement("TargetIQN")
|
|
entry.appendChild(subentry)
|
|
textnode = dom.createTextNode(record['targetIQN'])
|
|
subentry.appendChild(textnode)
|
|
return dom.toprettyxml()
|
|
|
|
def match_lun(self, s):
|
|
regex = re.compile("_")
|
|
if regex.search(s,0):
|
|
return False
|
|
regex = re.compile("LUN")
|
|
return regex.search(s, 0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
SRCommand.run(ISCSISR, DRIVER_INFO)
|
|
else:
|
|
SR.registerSR(ISCSISR)
|