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# LVHDoISCSISR: LVHD over ISCSI software initiator SR driver 

19# 

20 

21from sm_typing import override 

22 

23import SR 

24import VDI 

25import LVHDSR 

26import BaseISCSI 

27import SRCommand 

28import util 

29import scsiutil 

30import lvutil 

31import time 

32import os 

33import sys 

34import xs_errors 

35import xmlrpc.client 

36import mpath_cli 

37import iscsilib 

38import glob 

39import copy 

40import scsiutil 

41import xml.dom.minidom 

42 

43CAPABILITIES = ["SR_PROBE", "SR_UPDATE", "SR_METADATA", "SR_TRIM", 

44 "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", 

45 "VDI_GENERATE_CONFIG", "VDI_CLONE", "VDI_SNAPSHOT", 

46 "VDI_RESIZE", "ATOMIC_PAUSE", "VDI_RESET_ON_BOOT/2", 

47 "VDI_UPDATE", "VDI_MIRROR", "VDI_CONFIG_CBT", 

48 "VDI_ACTIVATE", "VDI_DEACTIVATE"] 

49 

50CONFIGURATION = [['SCSIid', 'The scsi_id of the destination LUN'], \ 

51 ['target', 'IP address or hostname of the iSCSI target'], \ 

52 ['targetIQN', 'The IQN of the target LUN group to be attached'], \ 

53 ['chapuser', 'The username to be used during CHAP authentication'], \ 

54 ['chappassword', 'The password to be used during CHAP authentication'], \ 

55 ['incoming_chapuser', 'The incoming username to be used during bi-directional CHAP authentication (optional)'], \ 

56 ['incoming_chappassword', 'The incoming password to be used during bi-directional CHAP authentication (optional)'], \ 

57 ['port', 'The network port number on which to query the target'], \ 

58 ['multihomed', 'Enable multi-homing to this target, true or false (optional, defaults to same value as host.other_config:multipathing)'], \ 

59 ['usediscoverynumber', 'The specific iscsi record index to use. (optional)'], \ 

60 ['allocation', 'Valid values are thick or thin (optional, defaults to thick)']] 

61 

62DRIVER_INFO = { 

63 'name': 'LVHD over iSCSI', 

64 'description': 'SR plugin which represents disks as Logical Volumes within a Volume Group created on an iSCSI LUN', 

65 'vendor': 'Citrix Systems Inc', 

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

67 'driver_version': '1.0', 

68 'required_api_version': '1.0', 

69 'capabilities': CAPABILITIES, 

70 'configuration': CONFIGURATION 

71 } 

72 

73 

74class LVHDoISCSISR(LVHDSR.LVHDSR): 

75 """LVHD over ISCSI storage repository""" 

76 

77 @override 

78 @staticmethod 

79 def handles(type) -> bool: 

80 if __name__ == '__main__': 

81 name = sys.argv[0] 

82 else: 

83 name = __name__ 

84 if name.endswith("LVMoISCSISR"): 

85 return type == "lvmoiscsi" 

86 if type == "lvhdoiscsi": 

87 return True 

88 return False 

89 

90 @override 

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

92 if not sr_uuid: 92 ↛ 94line 92 didn't jump to line 94, because the condition on line 92 was never true

93 # This is a probe call, generate a temp sr_uuid 

94 sr_uuid = util.gen_uuid() 

95 

96 # If this is a vdi command, don't initialise SR 

97 if util.isVDICommand(self.original_srcmd.cmd): 

98 self.SCSIid = self.dconf['SCSIid'] 

99 else: 

100 self.create_iscsi_sessions(sr_uuid) 

101 

102 LVHDSR.LVHDSR.load(self, sr_uuid) 

103 

104 def create_iscsi_sessions(self, sr_uuid): 

105 if 'target' in self.original_srcmd.dconf: 105 ↛ 107line 105 didn't jump to line 107, because the condition on line 105 was never false

106 self.original_srcmd.dconf['targetlist'] = self.original_srcmd.dconf['target'] 

107 iscsi = BaseISCSI.BaseISCSISR(self.original_srcmd, sr_uuid) 

108 self.iscsiSRs = [] 

109 self.iscsiSRs.append(iscsi) 

110 saved_exc = None 

111 targets = self.dconf['target'].split(',') 

112 if len(targets) > 1 or self.dconf['targetIQN'] == "*": 

113 # Instantiate multiple sessions 

114 self.iscsiSRs = [] 

115 if self.dconf['targetIQN'] == "*": 115 ↛ 118line 115 didn't jump to line 118, because the condition on line 115 was never false

116 IQN = "any" 

117 else: 

118 IQN = self.dconf['targetIQN'] 

119 dict = {} 

120 IQNstring = "" 

121 IQNs = [] 

122 try: 

123 if 'multiSession' in self.dconf: 

124 IQNs = self.dconf['multiSession'].split("|") 

125 for IQN in IQNs: 

126 if IQN: 

127 dict[IQN] = "" 

128 else: 

129 try: 

130 IQNs.remove(IQN) 

131 except: 

132 # Exceptions are not expected but just in case 

133 pass 

134 # Order in multiSession must be preserved. It is important for dual-controllers. 

135 # IQNstring cannot be built with a dictionary iteration because of this 

136 IQNstring = self.dconf['multiSession'] 

137 else: 

138 for tgt in targets: 138 ↛ 157line 138 didn't jump to line 157, because the loop on line 138 didn't complete

139 try: 

140 tgt_ip = util._convertDNS(tgt) 

141 except: 

142 raise xs_errors.XenError('DNSError') 

143 iscsilib.ensure_daemon_running_ok(iscsi.localIQN) 

144 map = iscsilib.discovery(tgt_ip, iscsi.port, iscsi.chapuser, iscsi.chappassword, targetIQN=IQN) 

145 util.SMlog("Discovery for IP %s returned %s" % (tgt, map)) 

146 for i in range(0, len(map)): 

147 (portal, tpgt, iqn) = map[i] 

148 (ipaddr, port) = iscsilib.parse_IP_port(portal) 

149 try: 

150 util._testHost(ipaddr, int(port), 'ISCSITarget') 

151 except: 

152 util.SMlog("Target Not reachable: (%s:%s)" % (ipaddr, port)) 

153 continue 

154 key = "%s,%s,%s" % (ipaddr, port, iqn) 

155 dict[key] = "" 

156 # Again, do not mess up with IQNs order. Dual controllers will benefit from that 

157 if IQNstring == "": 157 ↛ 159line 157 didn't jump to line 159, because the condition on line 157 was never true

158 # Compose the IQNstring first 

159 for key in dict.keys(): 

160 IQNstring += "%s|" % key 

161 # Reinitialize and store iterator 

162 key_iterator = iter(dict.keys()) 

163 else: 

164 key_iterator = IQNs 

165 

166 # Now load the individual iSCSI base classes 

167 for key in key_iterator: 

168 (ipaddr, port, iqn) = key.split(',') 

169 srcmd_copy = copy.deepcopy(self.original_srcmd) 

170 srcmd_copy.dconf['target'] = ipaddr 

171 srcmd_copy.dconf['targetIQN'] = iqn 

172 srcmd_copy.dconf['multiSession'] = IQNstring 

173 util.SMlog("Setting targetlist: %s" % srcmd_copy.dconf['targetlist']) 

174 self.iscsiSRs.append(BaseISCSI.BaseISCSISR(srcmd_copy, sr_uuid)) 

175 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref) 

176 if pbd is not None and 'multiSession' not in self.dconf: 176 ↛ 177line 176 didn't jump to line 177, because the condition on line 176 was never true

177 dconf = self.session.xenapi.PBD.get_device_config(pbd) 

178 dconf['multiSession'] = IQNstring 

179 self.session.xenapi.PBD.set_device_config(pbd, dconf) 

180 except Exception as exc: 

181 util.logException("LVHDoISCSISR.load") 

182 saved_exc = exc 

183 try: 

184 self.iscsi = self.iscsiSRs[0] 

185 except IndexError as exc: 

186 if isinstance(saved_exc, xs_errors.SROSError): 

187 raise saved_exc # pylint: disable-msg=E0702 

188 elif isinstance(saved_exc, Exception): 188 ↛ 191line 188 didn't jump to line 191, because the condition on line 188 was never false

189 raise xs_errors.XenError('SMGeneral', str(saved_exc)) 

190 else: 

191 raise xs_errors.XenError('SMGeneral', str(exc)) 

192 # Be extremely careful not to throw exceptions here since this function 

193 # is the main one used by all operations including probing and creating 

194 pbd = None 

195 try: 

196 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref) 

197 except: 

198 pass 

199 # Apart from the upgrade case, user must specify a SCSIid 

200 if 'SCSIid' not in self.dconf: 200 ↛ 202line 200 didn't jump to line 202, because the condition on line 200 was never true

201 # Dual controller issue 

202 self.LUNs = {} # Dict for LUNs from all the iscsi objects 

203 for ii in range(0, len(self.iscsiSRs)): 

204 self.iscsi = self.iscsiSRs[ii] 

205 self._LUNprint(sr_uuid) 

206 for key in self.iscsi.LUNs: 

207 self.LUNs[key] = self.iscsi.LUNs[key] 

208 self.print_LUNs_XML() 

209 self.iscsi = self.iscsiSRs[0] # back to original value 

210 raise xs_errors.XenError('ConfigSCSIid') 

211 self.SCSIid = self.dconf['SCSIid'] 

212 # This block checks if the first iscsi target contains the right SCSIid. 

213 # If not it scans the other iscsi targets because chances are that more 

214 # than one controller is present 

215 dev_match = False 

216 forced_login = False 

217 # No need to check if only one iscsi target is present 

218 if len(self.iscsiSRs) == 1: 

219 pass 

220 else: 

221 target_success = False 

222 attempt_discovery = False 

223 for iii in range(0, len(self.iscsiSRs)): 

224 # Check we didn't leave any iscsi session open 

225 # If exceptions happened before, the cleanup function has worked on the right target. 

226 if forced_login == True: 

227 try: 

228 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

229 iscsilib.logout(self.iscsi.target, self.iscsi.targetIQN) 

230 forced_login = False 

231 except: 

232 raise xs_errors.XenError('ISCSILogout') 

233 self.iscsi = self.iscsiSRs[iii] 

234 util.SMlog("path %s" % self.iscsi.path) 

235 util.SMlog("iscsci data: targetIQN %s, portal %s" % (self.iscsi.targetIQN, self.iscsi.target)) 

236 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

237 if not iscsilib._checkTGT(self.iscsi.targetIQN, self.iscsi.target): 237 ↛ 277line 237 didn't jump to line 277, because the condition on line 237 was never false

238 attempt_discovery = True 

239 try: 

240 # Ensure iscsi db has been populated 

241 map = iscsilib.discovery( 

242 self.iscsi.target, 

243 self.iscsi.port, 

244 self.iscsi.chapuser, 

245 self.iscsi.chappassword, 

246 targetIQN=self.iscsi.targetIQN) 

247 if len(map) == 0: 247 ↛ 248line 247 didn't jump to line 248, because the condition on line 247 was never true

248 util.SMlog("Discovery for iscsi data targetIQN %s," 

249 " portal %s returned empty list" 

250 " Trying another path if available" % 

251 (self.iscsi.targetIQN, 

252 self.iscsi.target)) 

253 continue 

254 except: 

255 util.SMlog("Discovery failed for iscsi data targetIQN" 

256 " %s, portal %s. Trying another path if" 

257 " available" % 

258 (self.iscsi.targetIQN, self.iscsi.target)) 

259 continue 

260 try: 

261 iscsilib.login(self.iscsi.target, 

262 self.iscsi.targetIQN, 

263 self.iscsi.chapuser, 

264 self.iscsi.chappassword, 

265 self.iscsi.incoming_chapuser, 

266 self.iscsi.incoming_chappassword, 

267 self.mpath == "true") 

268 except: 

269 util.SMlog("Login failed for iscsi data targetIQN %s," 

270 " portal %s. Trying another path" 

271 " if available" % 

272 (self.iscsi.targetIQN, self.iscsi.target)) 

273 continue 

274 target_success = True 

275 forced_login = True 

276 # A session should be active. 

277 if not util.wait_for_path(self.iscsi.path, BaseISCSI.MAX_TIMEOUT): 277 ↛ 278line 277 didn't jump to line 278, because the condition on line 277 was never true

278 util.SMlog("%s has no associated LUNs" % self.iscsi.targetIQN) 

279 continue 

280 scsiid_path = "/dev/disk/by-id/scsi-" + self.SCSIid 

281 if not util.wait_for_path(scsiid_path, BaseISCSI.MAX_TIMEOUT): 281 ↛ 282line 281 didn't jump to line 282, because the condition on line 281 was never true

282 util.SMlog("%s not found" % scsiid_path) 

283 continue 

284 for file in filter(self.iscsi.match_lun, util.listdir(self.iscsi.path)): 284 ↛ 285line 284 didn't jump to line 285, because the loop on line 284 never started

285 lun_path = os.path.join(self.iscsi.path, file) 

286 lun_dev = scsiutil.getdev(lun_path) 

287 try: 

288 lun_scsiid = scsiutil.getSCSIid(lun_dev) 

289 except: 

290 util.SMlog("getSCSIid failed on %s in iscsi %s: LUN" 

291 " offline or iscsi path down" % 

292 (lun_dev, self.iscsi.path)) 

293 continue 

294 util.SMlog("dev from lun %s %s" % (lun_dev, lun_scsiid)) 

295 if lun_scsiid == self.SCSIid: 

296 util.SMlog("lun match in %s" % self.iscsi.path) 

297 dev_match = True 

298 # No more need to raise ISCSITarget exception. 

299 # Resetting attempt_discovery 

300 attempt_discovery = False 

301 break 

302 if dev_match: 302 ↛ 303line 302 didn't jump to line 303, because the condition on line 302 was never true

303 if iii == 0: 

304 break 

305 util.SMlog("IQN reordering needed") 

306 new_iscsiSRs = [] 

307 IQNs = {} 

308 IQNstring = "" 

309 # iscsiSRs can be seen as a circular buffer: the head now is the matching one 

310 for kkk in list(range(iii, len(self.iscsiSRs))) + list(range(0, iii)): 

311 new_iscsiSRs.append(self.iscsiSRs[kkk]) 

312 ipaddr = self.iscsiSRs[kkk].target 

313 port = self.iscsiSRs[kkk].port 

314 iqn = self.iscsiSRs[kkk].targetIQN 

315 key = "%s,%s,%s" % (ipaddr, port, iqn) 

316 # The final string must preserve the order without repetition 

317 if key not in IQNs: 

318 IQNs[key] = "" 

319 IQNstring += "%s|" % key 

320 util.SMlog("IQNstring is now %s" % IQNstring) 

321 self.iscsiSRs = new_iscsiSRs 

322 util.SMlog("iqn %s is leading now" % self.iscsiSRs[0].targetIQN) 

323 # Updating pbd entry, if any 

324 try: 

325 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref) 

326 if pbd is not None and 'multiSession' in self.dconf: 

327 util.SMlog("Updating multiSession in PBD") 

328 dconf = self.session.xenapi.PBD.get_device_config(pbd) 

329 dconf['multiSession'] = IQNstring 

330 self.session.xenapi.PBD.set_device_config(pbd, dconf) 

331 except: 

332 pass 

333 break 

334 if not target_success and attempt_discovery: 334 ↛ 335line 334 didn't jump to line 335, because the condition on line 334 was never true

335 raise xs_errors.XenError('ISCSITarget') 

336 

337 # Check for any unneeded open iscsi sessions 

338 if forced_login == True: 338 ↛ exitline 338 didn't return from function 'create_iscsi_sessions', because the condition on line 338 was never false

339 try: 

340 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

341 iscsilib.logout(self.iscsi.target, self.iscsi.targetIQN) 

342 forced_login = False 

343 except: 

344 raise xs_errors.XenError('ISCSILogout') 

345 

346 def print_LUNs_XML(self): 

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

348 element = dom.createElement("iscsi-target") 

349 dom.appendChild(element) 

350 for uuid in self.LUNs: 

351 val = self.LUNs[uuid] 

352 entry = dom.createElement('LUN') 

353 element.appendChild(entry) 

354 

355 for attr in ('vendor', 'serial', 'LUNid', \ 

356 'size', 'SCSIid'): 

357 try: 

358 aval = getattr(val, attr) 

359 except AttributeError: 

360 continue 

361 

362 if aval: 

363 subentry = dom.createElement(attr) 

364 entry.appendChild(subentry) 

365 textnode = dom.createTextNode(str(aval)) 

366 subentry.appendChild(textnode) 

367 

368 print(dom.toprettyxml(), file=sys.stderr) 

369 

370 def _getSCSIid_from_LUN(self, sr_uuid): 

371 was_attached = True 

372 self.iscsi.attach(sr_uuid) 

373 dev = self.dconf['LUNid'].split(',') 

374 if len(dev) > 1: 

375 raise xs_errors.XenError('LVMOneLUN') 

376 path = os.path.join(self.iscsi.path, "LUN%s" % dev[0]) 

377 if not util.wait_for_path(path, BaseISCSI.MAX_TIMEOUT): 

378 util.SMlog("Unable to detect LUN attached to host [%s]" % path) 

379 try: 

380 SCSIid = scsiutil.getSCSIid(path) 

381 except: 

382 raise xs_errors.XenError('InvalidDev') 

383 self.iscsi.detach(sr_uuid) 

384 return SCSIid 

385 

386 def _LUNprint(self, sr_uuid): 

387 if self.iscsi.attached: 

388 # Force a rescan on the bus. 

389 self.iscsi.refresh() 

390# time.sleep(5) 

391# Now call attach (handles the refcounting + session activa) 

392 self.iscsi.attach(sr_uuid) 

393 

394 util.SMlog("LUNprint: waiting for path: %s" % self.iscsi.path) 

395 if util.wait_for_path("%s/LUN*" % self.iscsi.path, BaseISCSI.MAX_TIMEOUT): 

396 try: 

397 adapter = self.iscsi.adapter[self.iscsi.address] 

398 util.SMlog("adapter=%s" % adapter) 

399 

400 # find a scsi device on which to issue a report luns command: 

401 devs = glob.glob("%s/LUN*" % self.iscsi.path) 

402 sgdevs = [] 

403 for i in devs: 

404 sgdevs.append(int(i.split("LUN")[1])) 

405 sgdevs.sort() 

406 sgdev = "%s/LUN%d" % (self.iscsi.path, sgdevs[0]) 

407 

408 # issue a report luns: 

409 luns = util.pread2(["/usr/bin/sg_luns", "-q", sgdev]).split('\n') 

410 nluns = len(luns) - 1 # remove the line relating to the final \n 

411 

412 # make sure we've got that many sg devices present 

413 for i in range(0, 30): 

414 luns = scsiutil._dosgscan() 

415 sgdevs = [r for r in luns if r[1] == adapter] 

416 if len(sgdevs) >= nluns: 

417 util.SMlog("Got all %d sg devices" % nluns) 

418 break 

419 else: 

420 util.SMlog("Got %d sg devices - expecting %d" % (len(sgdevs), nluns)) 

421 time.sleep(1) 

422 

423 if os.path.exists("/sbin/udevsettle"): 

424 util.pread2(["/sbin/udevsettle"]) 

425 else: 

426 util.pread2(["/sbin/udevadm", "settle"]) 

427 except: 

428 util.SMlog("Generic exception caught. Pass") 

429 pass # Make sure we don't break the probe... 

430 

431 self.iscsi.print_LUNs() 

432 self.iscsi.detach(sr_uuid) 

433 

434 @override 

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

436 # Check SCSIid not already in use by other PBDs 

437 if util.test_SCSIid(self.session, sr_uuid, self.SCSIid): 

438 raise xs_errors.XenError('SRInUse') 

439 

440 self.iscsi.attach(sr_uuid) 

441 try: 

442 self.iscsi._attach_LUN_bySCSIid(self.SCSIid) 

443 self._pathrefresh(LVHDoISCSISR) 

444 LVHDSR.LVHDSR.create(self, sr_uuid, size) 

445 except Exception as inst: 

446 self.iscsi.detach(sr_uuid) 

447 raise xs_errors.XenError("SRUnavailable", opterr=inst) 

448 self.iscsi.detach(sr_uuid) 

449 

450 @override 

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

452 self._pathrefresh(LVHDoISCSISR) 

453 LVHDSR.LVHDSR.delete(self, sr_uuid) 

454 for i in self.iscsiSRs: 

455 i.detach(sr_uuid) 

456 

457 @override 

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

459 try: 

460 connected = False 

461 stored_exception = None 

462 for i in self.iscsiSRs: 

463 try: 

464 i.attach(sr_uuid) 

465 except xs_errors.SROSError as inst: 

466 # Some iscsi objects can fail login/discovery but not all. Storing exception 

467 if inst.errno in [141, 83]: 

468 util.SMlog("Connection failed for target %s, continuing.." % i.target) 

469 stored_exception = inst 

470 continue 

471 else: 

472 raise 

473 else: 

474 connected = True 

475 

476 i._attach_LUN_bySCSIid(self.SCSIid) 

477 

478 # Check if at least one iscsi succeeded 

479 if not connected and stored_exception: 479 ↛ 481line 479 didn't jump to line 481, because the condition on line 479 was never true

480 # pylint: disable=raising-bad-type 

481 raise stored_exception 

482 

483 if 'multiSession' in self.dconf: 483 ↛ 488line 483 didn't jump to line 488, because the condition on line 483 was never false

484 # Force a manual bus refresh 

485 for a in self.iscsi.adapter: 485 ↛ 486line 485 didn't jump to line 486, because the loop on line 485 never started

486 scsiutil.rescan([self.iscsi.adapter[a]]) 

487 

488 self._pathrefresh(LVHDoISCSISR) 

489 LVHDSR.LVHDSR.attach(self, sr_uuid) 

490 except Exception as inst: 

491 for i in self.iscsiSRs: 

492 i.detach(sr_uuid) 

493 raise xs_errors.XenError("SRUnavailable", opterr=inst) 

494 self._setMultipathableFlag(SCSIid=self.SCSIid) 

495 

496 @override 

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

498 LVHDSR.LVHDSR.detach(self, sr_uuid) 

499 for i in self.iscsiSRs: 

500 i.detach(sr_uuid) 

501 

502 @override 

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

504 self._pathrefresh(LVHDoISCSISR) 

505 if self.mpath == "true": 

506 for i in self.iscsiSRs: 

507 try: 

508 i.attach(sr_uuid) 

509 except xs_errors.SROSError: 

510 util.SMlog("Connection failed for target %s, continuing.." % i.target) 

511 LVHDSR.LVHDSR.scan(self, sr_uuid) 

512 

513 @override 

514 def probe(self) -> str: 

515 self.uuid = util.gen_uuid() 

516 

517 # When multipathing is enabled, since we don't refcount the multipath maps, 

518 # we should not attempt to do the iscsi.attach/detach when the map is already present, 

519 # as this will remove it (which may well be in use). 

520 if self.mpath == 'true' and 'SCSIid' in self.dconf: 

521 maps = [] 

522 try: 

523 maps = mpath_cli.list_maps() 

524 except: 

525 pass 

526 

527 if self.dconf['SCSIid'] in maps: 

528 raise xs_errors.XenError('SRInUse') 

529 

530 self.iscsi.attach(self.uuid) 

531 self.iscsi._attach_LUN_bySCSIid(self.SCSIid) 

532 self._pathrefresh(LVHDoISCSISR) 

533 out = LVHDSR.LVHDSR.probe(self) 

534 self.iscsi.detach(self.uuid) 

535 return out 

536 

537 @override 

538 def check_sr(self, sr_uuid) -> None: 

539 """Hook to check SR health""" 

540 pbdref = util.find_my_pbd(self.session, self.host_ref, self.sr_ref) 

541 if pbdref: 

542 other_config = self.session.xenapi.PBD.get_other_config(pbdref) 

543 if util.sessions_less_than_targets(other_config, self.dconf): 

544 self.create_iscsi_sessions(sr_uuid) 

545 for iscsi in self.iscsiSRs: 

546 try: 

547 iscsi.attach(sr_uuid) 

548 except xs_errors.SROSError: 

549 util.SMlog("Failed to attach iSCSI target") 

550 

551 @override 

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

553 return LVHDoISCSIVDI(self, uuid) 

554 

555 

556class LVHDoISCSIVDI(LVHDSR.LVHDVDI): 

557 @override 

558 def generate_config(self, sr_uuid, vdi_uuid) -> str: 

559 util.SMlog("LVHDoISCSIVDI.generate_config") 

560 if not lvutil._checkLV(self.path): 

561 raise xs_errors.XenError('VDIUnavailable') 

562 dict = {} 

563 self.sr.dconf['localIQN'] = self.sr.iscsi.localIQN 

564 self.sr.dconf['multipathing'] = self.sr.mpath 

565 self.sr.dconf['multipathhandle'] = self.sr.mpathhandle 

566 dict['device_config'] = self.sr.dconf 

567 if 'chappassword_secret' in dict['device_config']: 

568 s = util.get_secret(self.session, dict['device_config']['chappassword_secret']) 

569 del dict['device_config']['chappassword_secret'] 

570 dict['device_config']['chappassword'] = s 

571 dict['sr_uuid'] = sr_uuid 

572 dict['vdi_uuid'] = vdi_uuid 

573 dict['command'] = 'vdi_attach_from_config' 

574 # Return the 'config' encoded within a normal XMLRPC response so that 

575 # we can use the regular response/error parsing code. 

576 config = xmlrpc.client.dumps(tuple([dict]), "vdi_attach_from_config") 

577 return xmlrpc.client.dumps((config, ), "", True) 

578 

579 @override 

580 def attach_from_config(self, sr_uuid, vdi_uuid) -> str: 

581 util.SMlog("LVHDoISCSIVDI.attach_from_config") 

582 try: 

583 self.sr.iscsi.attach(sr_uuid) 

584 self.sr.iscsi._attach_LUN_bySCSIid(self.sr.SCSIid) 

585 return LVHDSR.LVHDVDI.attach(self, sr_uuid, vdi_uuid) 

586 except: 

587 util.logException("LVHDoISCSIVDI.attach_from_config") 

588 raise xs_errors.XenError('SRUnavailable', \ 

589 opterr='Unable to attach the heartbeat disk') 

590 

591 

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

593 SRCommand.run(LVHDoISCSISR, DRIVER_INFO) 

594else: 

595 SR.registerSR(LVHDoISCSISR)