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 

21import SR 

22import LVHDSR 

23import BaseISCSI 

24import SRCommand 

25import util 

26import scsiutil 

27import lvutil 

28import time 

29import os 

30import sys 

31import xs_errors 

32import xmlrpc.client 

33import mpath_cli 

34import iscsilib 

35import glob 

36import copy 

37import scsiutil 

38import xml.dom.minidom 

39 

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

41 "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", 

42 "VDI_GENERATE_CONFIG", "VDI_CLONE", "VDI_SNAPSHOT", 

43 "VDI_RESIZE", "ATOMIC_PAUSE", "VDI_RESET_ON_BOOT/2", 

44 "VDI_UPDATE", "VDI_MIRROR", "VDI_CONFIG_CBT", 

45 "VDI_ACTIVATE", "VDI_DEACTIVATE"] 

46 

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

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

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

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

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

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

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

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

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

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

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

58 

59DRIVER_INFO = { 

60 'name': 'LVHD over iSCSI', 

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

62 'vendor': 'Citrix Systems Inc', 

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

64 'driver_version': '1.0', 

65 'required_api_version': '1.0', 

66 'capabilities': CAPABILITIES, 

67 'configuration': CONFIGURATION 

68 } 

69 

70 

71class LVHDoISCSISR(LVHDSR.LVHDSR): 

72 """LVHD over ISCSI storage repository""" 

73 

74 def handles(type): 

75 if __name__ == '__main__': 

76 name = sys.argv[0] 

77 else: 

78 name = __name__ 

79 if name.endswith("LVMoISCSISR"): 

80 return type == "lvmoiscsi" 

81 if type == "lvhdoiscsi": 

82 return True 

83 return False 

84 handles = staticmethod(handles) 

85 

86 def load(self, sr_uuid): 

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

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

89 sr_uuid = util.gen_uuid() 

90 

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

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

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

94 else: 

95 self.create_iscsi_sessions(sr_uuid) 

96 

97 LVHDSR.LVHDSR.load(self, sr_uuid) 

98 

99 def create_iscsi_sessions(self, sr_uuid): 

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

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

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

103 self.iscsiSRs = [] 

104 self.iscsiSRs.append(iscsi) 

105 saved_exc = None 

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

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

108 # Instantiate multiple sessions 

109 self.iscsiSRs = [] 

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

111 IQN = "any" 

112 else: 

113 IQN = self.dconf['targetIQN'] 

114 dict = {} 

115 IQNstring = "" 

116 IQNs = [] 

117 try: 

118 if 'multiSession' in self.dconf: 

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

120 for IQN in IQNs: 

121 if IQN: 

122 dict[IQN] = "" 

123 else: 

124 try: 

125 IQNs.remove(IQN) 

126 except: 

127 # Exceptions are not expected but just in case 

128 pass 

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

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

131 IQNstring = self.dconf['multiSession'] 

132 else: 

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

134 try: 

135 tgt_ip = util._convertDNS(tgt) 

136 except: 

137 raise xs_errors.XenError('DNSError') 

138 iscsilib.ensure_daemon_running_ok(iscsi.localIQN) 

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

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

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

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

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

144 try: 

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

146 except: 

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

148 continue 

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

150 dict[key] = "" 

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

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

153 # Compose the IQNstring first 

154 for key in dict.keys(): 

155 IQNstring += "%s|" % key 

156 # Reinitialize and store iterator 

157 key_iterator = iter(dict.keys()) 

158 else: 

159 key_iterator = IQNs 

160 

161 # Now load the individual iSCSI base classes 

162 for key in key_iterator: 

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

164 srcmd_copy = copy.deepcopy(self.original_srcmd) 

165 srcmd_copy.dconf['target'] = ipaddr 

166 srcmd_copy.dconf['targetIQN'] = iqn 

167 srcmd_copy.dconf['multiSession'] = IQNstring 

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

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

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

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

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

173 dconf['multiSession'] = IQNstring 

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

175 except Exception as exc: 

176 util.logException("LVHDoISCSISR.load") 

177 saved_exc = exc 

178 try: 

179 self.iscsi = self.iscsiSRs[0] 

180 except IndexError as exc: 

181 if isinstance(saved_exc, xs_errors.SROSError): 

182 raise saved_exc # pylint: disable-msg=E0702 

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

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

185 else: 

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

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

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

189 pbd = None 

190 try: 

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

192 except: 

193 pass 

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

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

196 # Dual controller issue 

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

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

199 self.iscsi = self.iscsiSRs[ii] 

200 self._LUNprint(sr_uuid) 

201 for key in self.iscsi.LUNs: 

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

203 self.print_LUNs_XML() 

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

205 raise xs_errors.XenError('ConfigSCSIid') 

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

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

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

209 # than one controller is present 

210 dev_match = False 

211 forced_login = False 

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

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

214 pass 

215 else: 

216 target_success = False 

217 attempt_discovery = False 

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

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

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

221 if forced_login == True: 

222 try: 

223 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

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

225 forced_login = False 

226 except: 

227 raise xs_errors.XenError('ISCSILogout') 

228 self.iscsi = self.iscsiSRs[iii] 

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

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

231 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

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

233 attempt_discovery = True 

234 try: 

235 # Ensure iscsi db has been populated 

236 map = iscsilib.discovery( 

237 self.iscsi.target, 

238 self.iscsi.port, 

239 self.iscsi.chapuser, 

240 self.iscsi.chappassword, 

241 targetIQN=self.iscsi.targetIQN) 

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

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

244 " portal %s returned empty list" 

245 " Trying another path if available" % 

246 (self.iscsi.targetIQN, 

247 self.iscsi.target)) 

248 continue 

249 except: 

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

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

252 " available" % 

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

254 continue 

255 try: 

256 iscsilib.login(self.iscsi.target, 

257 self.iscsi.targetIQN, 

258 self.iscsi.chapuser, 

259 self.iscsi.chappassword, 

260 self.iscsi.incoming_chapuser, 

261 self.iscsi.incoming_chappassword, 

262 self.mpath == "true") 

263 except: 

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

265 " portal %s. Trying another path" 

266 " if available" % 

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

268 continue 

269 target_success = True 

270 forced_login = True 

271 # A session should be active. 

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

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

274 continue 

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

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

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

278 continue 

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

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

281 lun_dev = scsiutil.getdev(lun_path) 

282 try: 

283 lun_scsiid = scsiutil.getSCSIid(lun_dev) 

284 except: 

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

286 " offline or iscsi path down" % 

287 (lun_dev, self.iscsi.path)) 

288 continue 

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

290 if lun_scsiid == self.SCSIid: 

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

292 dev_match = True 

293 # No more need to raise ISCSITarget exception. 

294 # Resetting attempt_discovery 

295 attempt_discovery = False 

296 break 

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

298 if iii == 0: 

299 break 

300 util.SMlog("IQN reordering needed") 

301 new_iscsiSRs = [] 

302 IQNs = {} 

303 IQNstring = "" 

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

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

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

307 ipaddr = self.iscsiSRs[kkk].target 

308 port = self.iscsiSRs[kkk].port 

309 iqn = self.iscsiSRs[kkk].targetIQN 

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

311 # The final string must preserve the order without repetition 

312 if key not in IQNs: 

313 IQNs[key] = "" 

314 IQNstring += "%s|" % key 

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

316 self.iscsiSRs = new_iscsiSRs 

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

318 # Updating pbd entry, if any 

319 try: 

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

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

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

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

324 dconf['multiSession'] = IQNstring 

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

326 except: 

327 pass 

328 break 

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

330 raise xs_errors.XenError('ISCSITarget') 

331 

332 # Check for any unneeded open iscsi sessions 

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

334 try: 

335 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

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

337 forced_login = False 

338 except: 

339 raise xs_errors.XenError('ISCSILogout') 

340 

341 def print_LUNs_XML(self): 

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

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

344 dom.appendChild(element) 

345 for uuid in self.LUNs: 

346 val = self.LUNs[uuid] 

347 entry = dom.createElement('LUN') 

348 element.appendChild(entry) 

349 

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

351 'size', 'SCSIid'): 

352 try: 

353 aval = getattr(val, attr) 

354 except AttributeError: 

355 continue 

356 

357 if aval: 

358 subentry = dom.createElement(attr) 

359 entry.appendChild(subentry) 

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

361 subentry.appendChild(textnode) 

362 

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

364 

365 def _getSCSIid_from_LUN(self, sr_uuid): 

366 was_attached = True 

367 self.iscsi.attach(sr_uuid) 

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

369 if len(dev) > 1: 

370 raise xs_errors.XenError('LVMOneLUN') 

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

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

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

374 try: 

375 SCSIid = scsiutil.getSCSIid(path) 

376 except: 

377 raise xs_errors.XenError('InvalidDev') 

378 self.iscsi.detach(sr_uuid) 

379 return SCSIid 

380 

381 def _LUNprint(self, sr_uuid): 

382 if self.iscsi.attached: 

383 # Force a rescan on the bus. 

384 self.iscsi.refresh() 

385# time.sleep(5) 

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

387 self.iscsi.attach(sr_uuid) 

388 

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

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

391 try: 

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

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

394 

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

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

397 sgdevs = [] 

398 for i in devs: 

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

400 sgdevs.sort() 

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

402 

403 # issue a report luns: 

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

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

406 

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

408 for i in range(0, 30): 

409 luns = scsiutil._dosgscan() 

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

411 if len(sgdevs) >= nluns: 

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

413 break 

414 else: 

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

416 time.sleep(1) 

417 

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

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

420 else: 

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

422 except: 

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

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

425 

426 self.iscsi.print_LUNs() 

427 self.iscsi.detach(sr_uuid) 

428 

429 def create(self, sr_uuid, size): 

430 # Check SCSIid not already in use by other PBDs 

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

432 raise xs_errors.XenError('SRInUse') 

433 

434 self.iscsi.attach(sr_uuid) 

435 try: 

436 self.iscsi._attach_LUN_bySCSIid(self.SCSIid) 

437 self._pathrefresh(LVHDoISCSISR) 

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

439 except Exception as inst: 

440 self.iscsi.detach(sr_uuid) 

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

442 self.iscsi.detach(sr_uuid) 

443 

444 def delete(self, sr_uuid): 

445 self._pathrefresh(LVHDoISCSISR) 

446 LVHDSR.LVHDSR.delete(self, sr_uuid) 

447 for i in self.iscsiSRs: 

448 i.detach(sr_uuid) 

449 

450 def attach(self, sr_uuid): 

451 try: 

452 connected = False 

453 stored_exception = None 

454 for i in self.iscsiSRs: 

455 try: 

456 i.attach(sr_uuid) 

457 except xs_errors.SROSError as inst: 

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

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

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

461 stored_exception = inst 

462 continue 

463 else: 

464 raise 

465 else: 

466 connected = True 

467 

468 i._attach_LUN_bySCSIid(self.SCSIid) 

469 

470 # Check if at least one iscsi succeeded 

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

472 # pylint: disable=raising-bad-type 

473 raise stored_exception 

474 

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

476 # Force a manual bus refresh 

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

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

479 

480 self._pathrefresh(LVHDoISCSISR) 

481 LVHDSR.LVHDSR.attach(self, sr_uuid) 

482 except Exception as inst: 

483 for i in self.iscsiSRs: 

484 i.detach(sr_uuid) 

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

486 self._setMultipathableFlag(SCSIid=self.SCSIid) 

487 

488 def detach(self, sr_uuid): 

489 LVHDSR.LVHDSR.detach(self, sr_uuid) 

490 for i in self.iscsiSRs: 

491 i.detach(sr_uuid) 

492 

493 def scan(self, sr_uuid): 

494 self._pathrefresh(LVHDoISCSISR) 

495 if self.mpath == "true": 

496 for i in self.iscsiSRs: 

497 try: 

498 i.attach(sr_uuid) 

499 except xs_errors.SROSError: 

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

501 LVHDSR.LVHDSR.scan(self, sr_uuid) 

502 

503 def probe(self): 

504 self.uuid = util.gen_uuid() 

505 

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

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

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

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

510 maps = [] 

511 try: 

512 maps = mpath_cli.list_maps() 

513 except: 

514 pass 

515 

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

517 raise xs_errors.XenError('SRInUse') 

518 

519 self.iscsi.attach(self.uuid) 

520 self.iscsi._attach_LUN_bySCSIid(self.SCSIid) 

521 self._pathrefresh(LVHDoISCSISR) 

522 out = LVHDSR.LVHDSR.probe(self) 

523 self.iscsi.detach(self.uuid) 

524 return out 

525 

526 def check_sr(self, sr_uuid): 

527 """Hook to check SR health""" 

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

529 if pbdref: 

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

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

532 self.create_iscsi_sessions(sr_uuid) 

533 for iscsi in self.iscsiSRs: 

534 try: 

535 iscsi.attach(sr_uuid) 

536 except xs_errors.SROSError: 

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

538 

539 def vdi(self, uuid): 

540 return LVHDoISCSIVDI(self, uuid) 

541 

542 

543class LVHDoISCSIVDI(LVHDSR.LVHDVDI): 

544 def generate_config(self, sr_uuid, vdi_uuid): 

545 util.SMlog("LVHDoISCSIVDI.generate_config") 

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

547 raise xs_errors.XenError('VDIUnavailable') 

548 dict = {} 

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

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

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

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

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

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

555 del dict['device_config']['chappassword_secret'] 

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

557 dict['sr_uuid'] = sr_uuid 

558 dict['vdi_uuid'] = vdi_uuid 

559 dict['command'] = 'vdi_attach_from_config' 

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

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

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

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

564 

565 def attach_from_config(self, sr_uuid, vdi_uuid): 

566 util.SMlog("LVHDoISCSIVDI.attach_from_config") 

567 try: 

568 self.sr.iscsi.attach(sr_uuid) 

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

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

571 except: 

572 util.logException("LVHDoISCSIVDI.attach_from_config") 

573 raise xs_errors.XenError('SRUnavailable', \ 

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

575 

576 

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

578 SRCommand.run(LVHDoISCSISR, DRIVER_INFO) 

579else: 

580 SR.registerSR(LVHDoISCSISR)