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 

22from sm_typing import Dict, List, override 

23 

24import SR 

25import SRCommand 

26import VDI 

27import devscan 

28import scsiutil 

29import util 

30import LUNperVDI 

31import os 

32import time 

33import xs_errors 

34import xml.dom.minidom 

35 

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

37 "VDI_DETACH", "VDI_INTRODUCE"] 

38 

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

40 

41DRIVER_INFO = { 

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

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

44 'vendor': 'Citrix Systems Inc', 

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

46 'driver_version': '1.0', 

47 'required_api_version': '1.0', 

48 'capabilities': CAPABILITIES, 

49 'configuration': CONFIGURATION 

50 } 

51 

52 

53class HBASR(SR.SR): 

54 """HBA storage repository""" 

55 

56 @override 

57 @staticmethod 

58 def handles(type) -> bool: 

59 if type == "hba": 

60 return True 

61 return False 

62 

63 @override 

64 def load(self, sr_uuid) -> None: 

65 self.sr_vditype = 'phy' 

66 self.type = "any" 

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

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

69 self.attached = False 

70 self.procname = "" 

71 self.devs: Dict[str, List[str]] = {} 

72 

73 def _init_hbadict(self): 

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

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

76 self.hbadict = dict['devs'] 

77 self.hbas = dict['adt'] 

78 if len(self.hbas): 

79 self.attached = True 

80 self.devs = scsiutil.cacheSCSIidentifiers() 

81 

82 def _init_hba_hostname(self): 

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

84 

85 fc_xml = self._probe_hba() 

86 nodewwnval = '' 

87 try: 

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

89 infos = fcs.getElementsByTagName("HBAInfo") 

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

91 nodewwn = info.getElementsByTagName("nodeWWN") 

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

93 break 

94 except: 

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

96 return nodewwnval 

97 

98 def _init_hbas(self): 

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

100 

101 fc_xml = self._probe_hba() 

102 adt = {} 

103 try: 

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

105 infos = fcs.getElementsByTagName("HBAInfo") 

106 # HBAInfo --> Port --> portWWN 

107 # HBAInfo --> Port --> deviceName 

108 for info in infos: 

109 ports = info.getElementsByTagName("Port") 

110 for port in ports: 

111 portwwns = port.getElementsByTagName("portWWN") 

112 devnames = port.getElementsByTagName("deviceName") 

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

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

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

116 except: 

117 raise xs_errors.XenError('XMLParse', \ 

118 opterr='HBA scanning failed') 

119 return adt 

120 

121 def _probe_hba(self): 

122 try: 

123 # use sysfs tree to gather FC data 

124 

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

126 hbalist = dom.createElement("HBAInfoList") 

127 dom.appendChild(hbalist) 

128 

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

130 for host in hostlist: 

131 

132 hbainfo = dom.createElement("HBAInfo") 

133 hbalist.appendChild(hbainfo) 

134 

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

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

137 entry = dom.createElement("model") 

138 hbainfo.appendChild(entry) 

139 textnode = dom.createTextNode(sname) 

140 entry.appendChild(textnode) 

141 

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

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

144 nname = util.make_WWN(nname) 

145 entry = dom.createElement("nodeWWN") 

146 hbainfo.appendChild(entry) 

147 # adjust nodename to look like expected string 

148 textnode = dom.createTextNode(nname) 

149 entry.appendChild(textnode) 

150 

151 port = dom.createElement("Port") 

152 hbainfo.appendChild(port) 

153 

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

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

156 pname = util.make_WWN(pname) 

157 entry = dom.createElement("portWWN") 

158 port.appendChild(entry) 

159 # adjust nodename to look like expected string 

160 textnode = dom.createTextNode(pname) 

161 entry.appendChild(textnode) 

162 

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

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

165 entry = dom.createElement("state") 

166 port.appendChild(entry) 

167 # adjust nodename to look like expected string 

168 textnode = dom.createTextNode(state) 

169 entry.appendChild(textnode) 

170 

171 entry = dom.createElement("deviceName") 

172 port.appendChild(entry) 

173 # adjust nodename to look like expected string 

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

175 entry.appendChild(textnode) 

176 

177 return dom.toxml() 

178 except: 

179 raise xs_errors.XenError('XMLParse', \ 

180 opterr='HBA probe failed') 

181 

182 @override 

183 def attach(self, sr_uuid) -> None: 

184 self._mpathHandle() 

185 

186 @override 

187 def detach(self, sr_uuid) -> None: 

188 if util._containsVDIinuse(self): 

189 return 

190 return 

191 

192 @override 

193 def create(self, sr_uuid, size) -> None: 

194 # Check whether an SR already exists 

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

196 for sr in SRs: 

197 record = SRs[sr] 

198 sm_config = record["sm_config"] 

199 if 'datatype' in sm_config and \ 

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

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

202 raise xs_errors.XenError('SRInUse') 

203 self._init_hbadict() 

204 if not self.attached: 

205 raise xs_errors.XenError('InvalidDev', \ 

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

207 

208 if self._loadvdis() > 0: 

209 scanrecord = SR.ScanRecord(self) 

210 scanrecord.synchronise() 

211 try: 

212 self.detach(sr_uuid) 

213 except: 

214 pass 

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

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

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

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

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

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

221 

222 @override 

223 def delete(self, sr_uuid) -> None: 

224 self.detach(sr_uuid) 

225 return 

226 

227 @override 

228 def probe(self) -> str: 

229 self._init_hbadict() 

230 self.attach("") 

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

232 Recs = {} 

233 for sr in SRs: 

234 record = SRs[sr] 

235 sm_config = record["sm_config"] 

236 if 'datatype' in sm_config and \ 

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

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

239 return self.srlist_toxml(Recs) 

240 

241 @override 

242 def scan(self, sr_uuid) -> None: 

243 self._init_hbadict() 

244 if not self.passthrough: 

245 if not self.attached: 

246 raise xs_errors.XenError('SRUnavailable') 

247 # HBA adapter scan already forced a bus rescan 

248 # Sleep for 2 seconds to allow devices to settle 

249 time.sleep(2) 

250 self._loadvdis() 

251 self.physical_utilisation = self.physical_size 

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

253 if vdi.managed: 

254 self.physical_utilisation += vdi.size 

255 self.virtual_allocation = self.physical_utilisation 

256 super(HBASR, self).scan(sr_uuid) 

257 

258 def print_devs(self): 

259 self.attach("") 

260 self._init_hbadict() 

261 return devscan.scan(self) 

262 

263 # This function returns a dictionary of HBA attached LUNs 

264 def _loadvdis(self): 

265 if self.vdis: 

266 return 

267 

268 self._init_hbadict() 

269 count = 0 

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

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

272 if vdi_path not in self.devs: 

273 continue 

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

275 obj = self.vdi(uuid) 

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

277 ids = self.devs[vdi_path] 

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

279 self.vdis[uuid] = obj 

280 self.physical_size += obj.size 

281 count += 1 

282 return count 

283 

284 def _getLUNbySMconfig(self, sm_config): 

285 raise xs_errors.XenError('VDIUnavailable') 

286 

287 @override 

288 def vdi(self, uuid) -> VDI.VDI: 

289 return LUNperVDI.RAWVDI(self, uuid) 

290 

291 def srlist_toxml(self, SRs): 

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

293 element = dom.createElement("SRlist") 

294 dom.appendChild(element) 

295 

296 for val in SRs: 

297 record = SRs[val] 

298 entry = dom.createElement('SR') 

299 element.appendChild(entry) 

300 

301 subentry = dom.createElement("UUID") 

302 entry.appendChild(subentry) 

303 textnode = dom.createTextNode(val) 

304 subentry.appendChild(textnode) 

305 return dom.toprettyxml() 

306 

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

308 SRCommand.run(HBASR, DRIVER_INFO) 

309else: 

310 SR.registerSR(HBASR)