Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/python3 

2# 

3# Copyright (C) Citrix Systems Inc. 

4# 

5# This program is free software; you can redistribute it and/or modify 

6# it under the terms of the GNU Lesser General Public License as published 

7# by the Free Software Foundation; version 2.1 only. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU Lesser General Public License for more details. 

13# 

14# You should have received a copy of the GNU Lesser General Public License 

15# along with this program; if not, write to the Free Software Foundation, Inc., 

16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 

17# 

18# HBASR: Hardware HBA LUN driver, e.g. Fibre Channel or SAS or 

19# hardware based iSCSI 

20# 

21 

22import SR 

23import SRCommand 

24import devscan 

25import scsiutil 

26import util 

27import LUNperVDI 

28import os 

29import time 

30import xs_errors 

31import xml.dom.minidom 

32 

33CAPABILITIES = ["SR_PROBE", "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", 

34 "VDI_DETACH", "VDI_INTRODUCE"] 

35 

36CONFIGURATION = [['type', 'HBA type (optional) (e.g. FC, iSCSI, SAS etc..)']] 

37 

38DRIVER_INFO = { 

39 'name': 'HBA LUN-per-VDI driver', 

40 'description': 'SR plugin which represents LUNs as VDIs sourced by hardware HBA adapters, e.g. hardware-based iSCSI or FC support', 

41 'vendor': 'Citrix Systems Inc', 

42 'copyright': '(C) 2008 Citrix Systems Inc', 

43 'driver_version': '1.0', 

44 'required_api_version': '1.0', 

45 'capabilities': CAPABILITIES, 

46 'configuration': CONFIGURATION 

47 } 

48 

49 

50class HBASR(SR.SR): 

51 """HBA storage repository""" 

52 

53 def handles(type): 

54 if type == "hba": 

55 return True 

56 return False 

57 handles = staticmethod(handles) 

58 

59 def load(self, sr_uuid): 

60 self.sr_vditype = 'phy' 

61 self.type = "any" 

62 if 'type' in self.dconf and self.dconf['type']: 

63 self.type = self.dconf['type'] 

64 self.attached = False 

65 self.procname = "" 

66 self.devs = {} 

67 

68 def _init_hbadict(self): 

69 if not hasattr(self, "hbas"): 

70 dict = devscan.adapters(filterstr=self.type) 

71 self.hbadict = dict['devs'] 

72 self.hbas = dict['adt'] 

73 if len(self.hbas): 

74 self.attached = True 

75 self.devs = scsiutil.cacheSCSIidentifiers() 

76 

77 def _init_hba_hostname(self): 

78 """ get the HBA Host WWN information on this host function """ 

79 

80 fc_xml = self._probe_hba() 

81 nodewwnval = '' 

82 try: 

83 fcs = xml.dom.minidom.parseString(fc_xml) 

84 infos = fcs.getElementsByTagName("HBAInfo") 

85 for info in infos: 85 ↛ 91line 85 didn't jump to line 91, because the loop on line 85 didn't complete

86 nodewwn = info.getElementsByTagName("nodeWWN") 

87 nodewwnval = str(nodewwn[0].firstChild.nodeValue) 

88 break 

89 except: 

90 raise xs_errors.XenError('XMLParse', opterr='HBA Host WWN scanning failed') 

91 return nodewwnval 

92 

93 def _init_hbas(self): 

94 """ get the HBA information on this host function """ 

95 

96 fc_xml = self._probe_hba() 

97 adt = {} 

98 try: 

99 fcs = xml.dom.minidom.parseString(fc_xml) 

100 infos = fcs.getElementsByTagName("HBAInfo") 

101 # HBAInfo --> Port --> portWWN 

102 # HBAInfo --> Port --> deviceName 

103 for info in infos: 

104 ports = info.getElementsByTagName("Port") 

105 for port in ports: 

106 portwwns = port.getElementsByTagName("portWWN") 

107 devnames = port.getElementsByTagName("deviceName") 

108 portval = str(portwwns[0].firstChild.nodeValue) 

109 devpath = str(devnames[0].firstChild.nodeValue).split('/')[-1] 

110 adt[devpath] = portval.split()[0] 

111 except: 

112 raise xs_errors.XenError('XMLParse', \ 

113 opterr='HBA scanning failed') 

114 return adt 

115 

116 def _probe_hba(self): 

117 try: 

118 # use sysfs tree to gather FC data 

119 

120 dom = xml.dom.minidom.Document() 

121 hbalist = dom.createElement("HBAInfoList") 

122 dom.appendChild(hbalist) 

123 

124 hostlist = util.listdir("/sys/class/fc_host") 

125 for host in hostlist: 

126 

127 hbainfo = dom.createElement("HBAInfo") 

128 hbalist.appendChild(hbainfo) 

129 

130 cmd = ["cat", "/sys/class/fc_host/%s/symbolic_name" % host] 

131 sname = util.pread(cmd)[:-1] 

132 entry = dom.createElement("model") 

133 hbainfo.appendChild(entry) 

134 textnode = dom.createTextNode(sname) 

135 entry.appendChild(textnode) 

136 

137 cmd = ["cat", "/sys/class/fc_host/%s/node_name" % host] 

138 nname = util.pread(cmd)[:-1] 

139 nname = util.make_WWN(nname) 

140 entry = dom.createElement("nodeWWN") 

141 hbainfo.appendChild(entry) 

142 # adjust nodename to look like expected string 

143 textnode = dom.createTextNode(nname) 

144 entry.appendChild(textnode) 

145 

146 port = dom.createElement("Port") 

147 hbainfo.appendChild(port) 

148 

149 cmd = ["cat", "/sys/class/fc_host/%s/port_name" % host] 

150 pname = util.pread(cmd)[:-1] 

151 pname = util.make_WWN(pname) 

152 entry = dom.createElement("portWWN") 

153 port.appendChild(entry) 

154 # adjust nodename to look like expected string 

155 textnode = dom.createTextNode(pname) 

156 entry.appendChild(textnode) 

157 

158 cmd = ["cat", "/sys/class/fc_host/%s/port_state" % host] 

159 state = util.pread(cmd)[:-1] 

160 entry = dom.createElement("state") 

161 port.appendChild(entry) 

162 # adjust nodename to look like expected string 

163 textnode = dom.createTextNode(state) 

164 entry.appendChild(textnode) 

165 

166 entry = dom.createElement("deviceName") 

167 port.appendChild(entry) 

168 # adjust nodename to look like expected string 

169 textnode = dom.createTextNode("/sys/class/scsi_host/%s" % host) 

170 entry.appendChild(textnode) 

171 

172 return dom.toxml() 

173 except: 

174 raise xs_errors.XenError('XMLParse', \ 

175 opterr='HBA probe failed') 

176 

177 def attach(self, sr_uuid): 

178 self._mpathHandle() 

179 

180 def detach(self, sr_uuid): 

181 if util._containsVDIinuse(self): 

182 return 

183 return 

184 

185 def create(self, sr_uuid, size): 

186 # Check whether an SR already exists 

187 SRs = self.session.xenapi.SR.get_all_records() 

188 for sr in SRs: 

189 record = SRs[sr] 

190 sm_config = record["sm_config"] 

191 if 'datatype' in sm_config and \ 

192 sm_config['datatype'] == 'HBA' and \ 

193 sm_config['hbatype'] == self.type: 

194 raise xs_errors.XenError('SRInUse') 

195 self._init_hbadict() 

196 if not self.attached: 

197 raise xs_errors.XenError('InvalidDev', \ 

198 opterr=('No such HBA Device detected [%s]') % self.type) 

199 

200 if self._loadvdis() > 0: 

201 scanrecord = SR.ScanRecord(self) 

202 scanrecord.synchronise() 

203 try: 

204 self.detach(sr_uuid) 

205 except: 

206 pass 

207 self.sm_config = self.session.xenapi.SR.get_sm_config(self.sr_ref) 

208 self.sm_config['disktype'] = 'Raw' 

209 self.sm_config['datatype'] = 'HBA' 

210 self.sm_config['hbatype'] = self.type 

211 self.sm_config['multipathable'] = 'true' 

212 self.session.xenapi.SR.set_sm_config(self.sr_ref, self.sm_config) 

213 

214 def delete(self, sr_uuid): 

215 self.detach(sr_uuid) 

216 return 

217 

218 def probe(self): 

219 self._init_hbadict() 

220 self.attach("") 

221 SRs = self.session.xenapi.SR.get_all_records() 

222 Recs = {} 

223 for sr in SRs: 

224 record = SRs[sr] 

225 sm_config = record["sm_config"] 

226 if 'datatype' in sm_config and \ 

227 sm_config['datatype'] == 'HBA': 

228 Recs[record["uuid"]] = sm_config 

229 return self.srlist_toxml(Recs) 

230 

231 def scan(self, sr_uuid): 

232 self._init_hbadict() 

233 if not self.passthrough: 

234 if not self.attached: 

235 raise xs_errors.XenError('SRUnavailable') 

236 # HBA adapter scan already forced a bus rescan 

237 # Sleep for 2 seconds to allow devices to settle 

238 time.sleep(2) 

239 self._loadvdis() 

240 self.physical_utilisation = self.physical_size 

241 for uuid, vdi in self.vdis.items(): 

242 if vdi.managed: 

243 self.physical_utilisation += vdi.size 

244 self.virtual_allocation = self.physical_utilisation 

245 return super(HBASR, self).scan(sr_uuid) 

246 

247 def print_devs(self): 

248 self.attach("") 

249 self._init_hbadict() 

250 return devscan.scan(self) 

251 

252 # This function returns a dictionary of HBA attached LUNs 

253 def _loadvdis(self): 

254 if self.vdis: 

255 return 

256 

257 self._init_hbadict() 

258 count = 0 

259 for key in self.hbadict.keys(): 

260 vdi_path = os.path.join("/dev", key) 

261 if vdi_path not in self.devs: 

262 continue 

263 uuid = scsiutil.gen_uuid_from_string(scsiutil.getuniqueserial(vdi_path)) 

264 obj = self.vdi(uuid) 

265 path = self.mpathmodule.path(scsiutil.getSCSIid(vdi_path)) 

266 ids = self.devs[vdi_path] 

267 obj._query(vdi_path, ids[4]) 

268 self.vdis[uuid] = obj 

269 self.physical_size += obj.size 

270 count += 1 

271 return count 

272 

273 def _getLUNbySMconfig(self, sm_config): 

274 raise xs_errors.XenError('VDIUnavailable') 

275 

276 def vdi(self, uuid): 

277 return LUNperVDI.RAWVDI(self, uuid) 

278 

279 def srlist_toxml(self, SRs): 

280 dom = xml.dom.minidom.Document() 

281 element = dom.createElement("SRlist") 

282 dom.appendChild(element) 

283 

284 for val in SRs: 

285 record = SRs[val] 

286 entry = dom.createElement('SR') 

287 element.appendChild(entry) 

288 

289 subentry = dom.createElement("UUID") 

290 entry.appendChild(subentry) 

291 textnode = dom.createTextNode(val) 

292 subentry.appendChild(textnode) 

293 return dom.toprettyxml() 

294 

295if __name__ == '__main__': 295 ↛ 296line 295 didn't jump to line 296, because the condition on line 295 was never true

296 SRCommand.run(HBASR, DRIVER_INFO) 

297else: 

298 SR.registerSR(HBASR)