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 if self.dconf['target'].find(',') == 0 or self.dconf['targetIQN'] == "*": 

107 # Instantiate multiple sessions 

108 self.iscsiSRs = [] 

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

110 IQN = "any" 

111 else: 

112 IQN = self.dconf['targetIQN'] 

113 dict = {} 

114 IQNstring = "" 

115 IQNs = [] 

116 try: 

117 if 'multiSession' in self.dconf: 117 ↛ 118line 117 didn't jump to line 118, because the condition on line 117 was never true

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

119 for IQN in IQNs: 

120 if IQN: 

121 dict[IQN] = "" 

122 else: 

123 try: 

124 IQNs.remove(IQN) 

125 except: 

126 # Exceptions are not expected but just in case 

127 pass 

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

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

130 IQNstring = self.dconf['multiSession'] 

131 else: 

132 for tgt in self.dconf['target'].split(','): 132 ↛ 151line 132 didn't jump to line 151, because the loop on line 132 didn't complete

133 try: 

134 tgt_ip = util._convertDNS(tgt) 

135 except: 

136 raise xs_errors.XenError('DNSError') 

137 iscsilib.ensure_daemon_running_ok(iscsi.localIQN) 

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

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

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

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

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

143 try: 

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

145 except: 

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

147 continue 

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

149 dict[key] = "" 

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

151 if IQNstring == "": 

152 # Compose the IQNstring first 

153 for key in dict.keys(): 

154 IQNstring += "%s|" % key 

155 # Reinitialize and store iterator 

156 key_iterator = iter(dict.keys()) 

157 else: 

158 key_iterator = IQNs 

159 

160 # Now load the individual iSCSI base classes 

161 for key in key_iterator: 

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

163 srcmd_copy = copy.deepcopy(self.original_srcmd) 

164 srcmd_copy.dconf['target'] = ipaddr 

165 srcmd_copy.dconf['targetIQN'] = iqn 

166 srcmd_copy.dconf['multiSession'] = IQNstring 

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

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

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

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

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

172 dconf['multiSession'] = IQNstring 

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

174 except Exception as exc: 

175 util.logException("LVHDoISCSISR.load") 

176 saved_exc = exc 

177 try: 

178 self.iscsi = self.iscsiSRs[0] 

179 except IndexError as exc: 

180 if isinstance(saved_exc, SR.SROSError): 

181 raise saved_exc # pylint: disable-msg=E0702 

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

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

184 else: 

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

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

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

188 pbd = None 

189 try: 

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

191 except: 

192 pass 

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

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

195 # Dual controller issue 

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

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

198 self.iscsi = self.iscsiSRs[ii] 

199 self._LUNprint(sr_uuid) 

200 for key in self.iscsi.LUNs: 

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

202 self.print_LUNs_XML() 

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

204 raise xs_errors.XenError('ConfigSCSIid') 

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

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

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

208 # than one controller is present 

209 dev_match = False 

210 forced_login = False 

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

212 if len(self.iscsiSRs) == 1: 212 ↛ 215line 212 didn't jump to line 215, because the condition on line 212 was never false

213 pass 

214 else: 

215 target_success = False 

216 attempt_discovery = False 

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

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

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

220 if forced_login == True: 

221 try: 

222 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

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

224 forced_login = False 

225 except: 

226 raise xs_errors.XenError('ISCSILogout') 

227 self.iscsi = self.iscsiSRs[iii] 

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

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

230 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

231 if not iscsilib._checkTGT(self.iscsi.targetIQN): 

232 attempt_discovery = True 

233 try: 

234 # Ensure iscsi db has been populated 

235 map = iscsilib.discovery( 

236 self.iscsi.target, 

237 self.iscsi.port, 

238 self.iscsi.chapuser, 

239 self.iscsi.chappassword, 

240 targetIQN=self.iscsi.targetIQN) 

241 if len(map) == 0: 

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

243 " portal %s returned empty list" 

244 " Trying another path if available" % 

245 (self.iscsi.targetIQN, 

246 self.iscsi.target)) 

247 continue 

248 except: 

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

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

251 " available" % 

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

253 continue 

254 try: 

255 iscsilib.login(self.iscsi.target, 

256 self.iscsi.targetIQN, 

257 self.iscsi.chapuser, 

258 self.iscsi.chappassword, 

259 self.iscsi.incoming_chapuser, 

260 self.iscsi.incoming_chappassword, 

261 self.mpath == "true") 

262 except: 

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

264 " portal %s. Trying another path" 

265 " if available" % 

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

267 continue 

268 target_success = True 

269 forced_login = True 

270 # A session should be active. 

271 if not util.wait_for_path(self.iscsi.path, BaseISCSI.MAX_TIMEOUT): 

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

273 continue 

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

275 if not util.wait_for_path(scsiid_path, BaseISCSI.MAX_TIMEOUT): 

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

277 continue 

278 for file in filter(self.iscsi.match_lun, util.listdir(self.iscsi.path)): 

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

280 lun_dev = scsiutil.getdev(lun_path) 

281 try: 

282 lun_scsiid = scsiutil.getSCSIid(lun_dev) 

283 except: 

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

285 " offline or iscsi path down" % 

286 (lun_dev, self.iscsi.path)) 

287 continue 

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

289 if lun_scsiid == self.SCSIid: 

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

291 dev_match = True 

292 # No more need to raise ISCSITarget exception. 

293 # Resetting attempt_discovery 

294 attempt_discovery = False 

295 break 

296 if dev_match: 

297 if iii == 0: 

298 break 

299 util.SMlog("IQN reordering needed") 

300 new_iscsiSRs = [] 

301 IQNs = {} 

302 IQNstring = "" 

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

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

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

306 ipaddr = self.iscsiSRs[kkk].target 

307 port = self.iscsiSRs[kkk].port 

308 iqn = self.iscsiSRs[kkk].targetIQN 

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

310 # The final string must preserve the order without repetition 

311 if key not in IQNs: 

312 IQNs[key] = "" 

313 IQNstring += "%s|" % key 

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

315 self.iscsiSRs = new_iscsiSRs 

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

317 # Updating pbd entry, if any 

318 try: 

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

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

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

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

323 dconf['multiSession'] = IQNstring 

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

325 except: 

326 pass 

327 break 

328 if not target_success and attempt_discovery: 

329 raise xs_errors.XenError('ISCSITarget') 

330 

331 # Check for any unneeded open iscsi sessions 

332 if forced_login == True: 

333 try: 

334 iscsilib.ensure_daemon_running_ok(self.iscsi.localIQN) 

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

336 forced_login = False 

337 except: 

338 raise xs_errors.XenError('ISCSILogout') 

339 

340 def print_LUNs_XML(self): 

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

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

343 dom.appendChild(element) 

344 for uuid in self.LUNs: 

345 val = self.LUNs[uuid] 

346 entry = dom.createElement('LUN') 

347 element.appendChild(entry) 

348 

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

350 'size', 'SCSIid'): 

351 try: 

352 aval = getattr(val, attr) 

353 except AttributeError: 

354 continue 

355 

356 if aval: 

357 subentry = dom.createElement(attr) 

358 entry.appendChild(subentry) 

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

360 subentry.appendChild(textnode) 

361 

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

363 

364 def _getSCSIid_from_LUN(self, sr_uuid): 

365 was_attached = True 

366 self.iscsi.attach(sr_uuid) 

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

368 if len(dev) > 1: 

369 raise xs_errors.XenError('LVMOneLUN') 

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

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

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

373 try: 

374 SCSIid = scsiutil.getSCSIid(path) 

375 except: 

376 raise xs_errors.XenError('InvalidDev') 

377 self.iscsi.detach(sr_uuid) 

378 return SCSIid 

379 

380 def _LUNprint(self, sr_uuid): 

381 if self.iscsi.attached: 

382 # Force a rescan on the bus. 

383 self.iscsi.refresh() 

384# time.sleep(5) 

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

386 self.iscsi.attach(sr_uuid) 

387 

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

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

390 try: 

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

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

393 

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

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

396 sgdevs = [] 

397 for i in devs: 

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

399 sgdevs.sort() 

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

401 

402 # issue a report luns: 

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

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

405 

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

407 for i in range(0, 30): 

408 luns = scsiutil._dosgscan() 

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

410 if len(sgdevs) >= nluns: 

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

412 break 

413 else: 

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

415 time.sleep(1) 

416 

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

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

419 else: 

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

421 except: 

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

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

424 

425 self.iscsi.print_LUNs() 

426 self.iscsi.detach(sr_uuid) 

427 

428 def create(self, sr_uuid, size): 

429 # Check SCSIid not already in use by other PBDs 

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

431 raise xs_errors.XenError('SRInUse') 

432 

433 self.iscsi.attach(sr_uuid) 

434 try: 

435 self.iscsi._attach_LUN_bySCSIid(self.SCSIid) 

436 self._pathrefresh(LVHDoISCSISR) 

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

438 except Exception as inst: 

439 self.iscsi.detach(sr_uuid) 

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

441 self.iscsi.detach(sr_uuid) 

442 

443 def delete(self, sr_uuid): 

444 self._pathrefresh(LVHDoISCSISR) 

445 LVHDSR.LVHDSR.delete(self, sr_uuid) 

446 for i in self.iscsiSRs: 

447 i.detach(sr_uuid) 

448 

449 def attach(self, sr_uuid): 

450 try: 

451 connected = False 

452 for i in self.iscsiSRs: 

453 try: 

454 i.attach(sr_uuid) 

455 except SR.SROSError as inst: 

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

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

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

459 stored_exception = inst 

460 continue 

461 else: 

462 raise 

463 else: 

464 connected = True 

465 

466 i._attach_LUN_bySCSIid(self.SCSIid) 

467 

468 # Check if at least one iscsi succeeded 

469 if not connected: 

470 raise stored_exception 

471 

472 if 'multiSession' in self.dconf: 

473 # Force a manual bus refresh 

474 for a in self.iscsi.adapter: 

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

476 

477 self._pathrefresh(LVHDoISCSISR) 

478 LVHDSR.LVHDSR.attach(self, sr_uuid) 

479 except Exception as inst: 

480 for i in self.iscsiSRs: 

481 i.detach(sr_uuid) 

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

483 self._setMultipathableFlag(SCSIid=self.SCSIid) 

484 

485 def detach(self, sr_uuid): 

486 LVHDSR.LVHDSR.detach(self, sr_uuid) 

487 for i in self.iscsiSRs: 

488 i.detach(sr_uuid) 

489 

490 def scan(self, sr_uuid): 

491 self._pathrefresh(LVHDoISCSISR) 

492 if self.mpath == "true": 

493 for i in self.iscsiSRs: 

494 try: 

495 i.attach(sr_uuid) 

496 except SR.SROSError: 

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

498 LVHDSR.LVHDSR.scan(self, sr_uuid) 

499 

500 def probe(self): 

501 self.uuid = util.gen_uuid() 

502 

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

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

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

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

507 maps = [] 

508 try: 

509 maps = mpath_cli.list_maps() 

510 except: 

511 pass 

512 

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

514 raise xs_errors.XenError('SRInUse') 

515 

516 self.iscsi.attach(self.uuid) 

517 self.iscsi._attach_LUN_bySCSIid(self.SCSIid) 

518 self._pathrefresh(LVHDoISCSISR) 

519 out = LVHDSR.LVHDSR.probe(self) 

520 self.iscsi.detach(self.uuid) 

521 return out 

522 

523 def check_sr(self, sr_uuid): 

524 """Hook to check SR health""" 

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

526 if pbdref: 

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

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

529 self.create_iscsi_sessions(sr_uuid) 

530 for iscsi in self.iscsiSRs: 

531 try: 

532 iscsi.attach(sr_uuid) 

533 except SR.SROSError: 

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

535 

536 def vdi(self, uuid): 

537 return LVHDoISCSIVDI(self, uuid) 

538 

539 

540class LVHDoISCSIVDI(LVHDSR.LVHDVDI): 

541 def generate_config(self, sr_uuid, vdi_uuid): 

542 util.SMlog("LVHDoISCSIVDI.generate_config") 

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

544 raise xs_errors.XenError('VDIUnavailable') 

545 dict = {} 

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

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

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

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

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

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

552 del dict['device_config']['chappassword_secret'] 

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

554 dict['sr_uuid'] = sr_uuid 

555 dict['vdi_uuid'] = vdi_uuid 

556 dict['command'] = 'vdi_attach_from_config' 

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

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

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

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

561 

562 def attach_from_config(self, sr_uuid, vdi_uuid): 

563 util.SMlog("LVHDoISCSIVDI.attach_from_config") 

564 try: 

565 self.sr.iscsi.attach(sr_uuid) 

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

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

568 except: 

569 util.logException("LVHDoISCSIVDI.attach_from_config") 

570 raise xs_errors.XenError('SRUnavailable', \ 

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

572 

573 

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

575 SRCommand.run(LVHDoISCSISR, DRIVER_INFO) 

576else: 

577 SR.registerSR(LVHDoISCSISR)