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# Copyright (C) Citrix Systems Inc. 

2# 

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

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

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

6# 

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

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

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

10# GNU Lesser General Public License for more details. 

11# 

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

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

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

15 

16INITIATORNAME_FILE = '/etc/iscsi/initiatorname.iscsi' 

17 

18import util 

19import os 

20import scsiutil 

21import time 

22import socket 

23import re 

24import shutil 

25import xs_errors 

26import lock 

27import glob 

28import tempfile 

29from configparser import RawConfigParser 

30import io 

31 

32# The 3.x kernel brings with it some iSCSI path changes in sysfs 

33_KERNEL_VERSION = os.uname()[2] 

34if _KERNEL_VERSION.startswith('2.6'): 34 ↛ 35line 34 didn't jump to line 35, because the condition on line 34 was never true

35 _GENERIC_SESSION_PATH = ('/sys/class/iscsi_host/host%s/device/session*/' + 

36 'iscsi_session*/') 

37 _GENERIC_CONNECTION_PATH = ('/sys/class/iscsi_host/host%s/device/' + 

38 'session*/connection*/iscsi_connection*/') 

39else: 

40 _GENERIC_SESSION_PATH = ('/sys/class/iscsi_host/host%s/device/session*/' + 

41 'iscsi_session/session*/') 

42 _GENERIC_CONNECTION_PATH = ('/sys/class/iscsi_host/host%s/device/' + 

43 'session*/connection*/iscsi_connection/connection*/') 

44 

45_REPLACEMENT_TMO_MPATH = 15 

46_REPLACEMENT_TMO_DEFAULT = 144 

47_REPLACEMENT_TMO_STANDARD = 120 

48 

49_ISCSI_DB_PATH = '/var/lib/iscsi' 

50 

51 

52def doexec_locked(cmd): 

53 """Executes via util.doexec the command specified whilst holding lock""" 

54 _lock = None 

55 if os.path.basename(cmd[0]) == 'iscsiadm': 

56 _lock = lock.Lock(lock.LOCK_TYPE_ISCSIADM_RUNNING, 'iscsiadm') 

57 _lock.acquire() 

58 # util.SMlog("%s" % cmd) 

59 (rc, stdout, stderr) = util.doexec(cmd) 

60 if _lock is not None and _lock.held(): 

61 _lock.release() 

62 return (rc, stdout, stderr) 

63 

64 

65def noexn_on_failure(cmd): 

66 """Executes via util.doexec the command specified as best effort.""" 

67 (rc, stdout, stderr) = doexec_locked(cmd) 

68 return (stdout, stderr) 

69 

70 

71def exn_on_failure(cmd, message): 

72 """Executes via util.doexec the command specified. If the return code is 

73 non-zero, raises an ISCSIError with the given message""" 

74 (rc, stdout, stderr) = doexec_locked(cmd) 

75 if rc == 0: 

76 return (stdout, stderr) 

77 else: 

78 msg = 'rc: %d, stdout: %s, stderr: %s' % (rc, stdout, stderr) 

79 raise xs_errors.XenError('SMGeneral', opterr=msg) 

80 

81 

82def parse_node_output(text, targetIQN): 

83 """helper function - parses the output of iscsiadm for discovery and 

84 get_node_records""" 

85 

86 def dotrans(x): 

87 (rec, iqn) = x.split() 

88 (portal, tpgt) = rec.split(',') 

89 return (portal, tpgt, iqn) 

90 unfiltered_map = [dotrans(x) for x in text.split('\n') if 

91 match_targetIQN(targetIQN, x)] 

92 # We need to filter duplicates orignating from doing the discovery using 

93 # multiple interfaces 

94 filtered_map = [] 

95 for input_value in unfiltered_map: 

96 if input_value not in filtered_map: 96 ↛ 95line 96 didn't jump to line 95, because the condition on line 96 was never false

97 filtered_map.append(input_value) 

98 return filtered_map 

99 

100 

101def parse_IP_port(portal): 

102 """Extract IP address and port number from portal information. 

103 

104 Input: String encoding the IP address and port of form: 

105 - x.x.x.x:p (IPv4) 

106 or 

107 - [xxxx:xxxx:...:xxxx]:p (IPv6) 

108 

109 Return tuple of IP and port (without square brackets in case of IPv6): 

110 """ 

111 (ipaddr, port) = portal.split(',')[0].rsplit(':', 1) 

112 if ipaddr[0] == '[': 112 ↛ 114line 112 didn't jump to line 114, because the condition on line 112 was never true

113 # This is IPv6, strip off [ ] surround 

114 ipaddr = ipaddr[1:-1] 

115 return (ipaddr, port) 

116 

117 

118def save_rootdisk_nodes(tmpdirname): 

119 root_iqns = get_rootdisk_IQNs() 

120 if root_iqns: 

121 srcdirs = [os.path.join(_ISCSI_DB_PATH, 'nodes', iqn) for iqn in root_iqns] 

122 util.doexec(['/bin/cp', '-a'] + srcdirs + [tmpdirname]) 

123 

124 

125def restore_rootdisk_nodes(tmpdirname): 

126 root_iqns = get_rootdisk_IQNs() 

127 if root_iqns: 

128 srcdirs = [os.path.join(tmpdirname, iqn) for iqn in root_iqns] 

129 util.doexec(['/bin/cp', '-a'] + srcdirs + 

130 [os.path.join(_ISCSI_DB_PATH, 'nodes')]) 

131 

132 

133def discovery(target, port, chapuser, chappass, targetIQN="any", 

134 interfaceArray=["default"]): 

135 """Run iscsiadm in discovery mode to obtain a list of the  

136 TargetIQNs available on the specified target and port. Returns 

137 a list of triples - the portal (ip:port), the tpgt (target portal 

138 group tag) and the target name""" 

139 

140 # Save configuration of root LUN nodes and restore after discovery 

141 # otherwise when we do a discovery on the same filer as is hosting 

142 # our root disk we'll reset the config of the root LUNs 

143 

144 # FIXME: Replace this with TemporaryDirectory when moving to Python3 

145 tmpdirname = tempfile.mkdtemp() 

146 try: 

147 save_rootdisk_nodes(tmpdirname) 

148 

149 if ':' in target: 149 ↛ 150line 149 didn't jump to line 150, because the condition on line 149 was never true

150 targetstring = "[%s]:%s" % (target, str(port)) 

151 else: 

152 targetstring = "%s:%s" % (target, str(port)) 

153 cmd_base = ["-t", "st", "-p", targetstring] 

154 for interface in interfaceArray: 

155 cmd_base.append("-I") 

156 cmd_base.append(interface) 

157 cmd_disc = ["iscsiadm", "-m", "discovery"] + cmd_base 

158 cmd_discdb = ["iscsiadm", "-m", "discoverydb"] + cmd_base 

159 auth_args = ["-n", "discovery.sendtargets.auth.authmethod", "-v", "CHAP", 

160 "-n", "discovery.sendtargets.auth.username", "-v", chapuser, 

161 "-n", "discovery.sendtargets.auth.password", "-v", chappass] 

162 fail_msg = "Discovery failed. Check target settings and " \ 

163 "username/password (if applicable)" 

164 try: 

165 if chapuser != "" and chappass != "": 

166 exn_on_failure(cmd_discdb + ["-o", "new"], fail_msg) 

167 exn_on_failure(cmd_discdb + ["-o", "update"] + auth_args, fail_msg) 

168 cmd = cmd_discdb + ["--discover"] 

169 else: 

170 cmd = cmd_disc 

171 (stdout, stderr) = exn_on_failure(cmd, fail_msg) 

172 except: 

173 raise xs_errors.XenError('ISCSILogin') 

174 finally: 

175 restore_rootdisk_nodes(tmpdirname) 

176 finally: 

177 shutil.rmtree(tmpdirname) 177 ↛ exitline 177 didn't except from function 'discovery', because the raise on line 173 wasn't executed

178 

179 return parse_node_output(stdout, targetIQN) 

180 

181 

182def get_node_records(targetIQN="any"): 

183 """Return the node records that the iscsi daemon already knows about""" 

184 cmd = ["iscsiadm", "-m", "node"] 

185 failuremessage = "Failed to obtain node records from iscsi daemon" 

186 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

187 return parse_node_output(stdout, targetIQN) 

188 

189 

190def set_chap_settings (portal, targetIQN, username, password, username_in, password_in): 

191 """Sets the username and password on the session identified by the  

192 portal/targetIQN combination""" 

193 failuremessage = "Failed to set CHAP settings" 

194 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

195 "update", "-n", "node.session.auth.authmethod", "-v", "CHAP"] 

196 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

197 

198 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

199 "update", "-n", "node.session.auth.username", "-v", 

200 username] 

201 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

202 

203 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

204 "update", "-n", "node.session.auth.password", "-v", 

205 password] 

206 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

207 

208 if (username_in != ""): 

209 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

210 "update", "-n", "node.session.auth.username_in", "-v", 

211 username_in] 

212 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

213 

214 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

215 "update", "-n", "node.session.auth.password_in", "-v", 

216 password_in] 

217 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

218 

219 

220def remove_chap_settings(portal, targetIQN): 

221 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

222 "update", "-n", "node.session.auth.authmethod", "-v", "None"] 

223 (stdout, stderr) = noexn_on_failure(cmd) 

224 

225 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

226 "update", "-n", "node.session.auth.username", "-v", ""] 

227 (stdout, stderr) = noexn_on_failure(cmd) 

228 

229 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

230 "update", "-n", "node.session.auth.password", "-v", ""] 

231 (stdout, stderr) = noexn_on_failure(cmd) 

232 

233 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

234 "update", "-n", "node.session.auth.username_in", "-v", ""] 

235 (stdout, stderr) = noexn_on_failure(cmd) 

236 

237 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "--op", 

238 "update", "-n", "node.session.auth.password_in", "-v", ""] 

239 (stdout, stderr) = noexn_on_failure(cmd) 

240 

241 

242def get_node_config (portal, targetIQN): 

243 """ Using iscsadm to get the current configuration of a iscsi node. 

244 The output is parsed in ini format, and returned as a dictionary.""" 

245 failuremessage = "Failed to get node configurations" 

246 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", targetIQN, "-S"] 

247 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

248 ini_sec = "root" 

249 str_fp = io.StringIO("[%s]\n%s" % (ini_sec, stdout)) 

250 parser = RawConfigParser() 

251 parser.readfp(str_fp) 

252 str_fp.close() 

253 return dict(parser.items(ini_sec)) 

254 

255 

256def set_replacement_tmo (portal, targetIQN, mpath): 

257 key = "node.session.timeo.replacement_timeout" 

258 try: 

259 current_tmo = int((get_node_config(portal, targetIQN))[key]) 

260 except: 

261 # Assume a standard TMO setting if get_node_config fails 

262 current_tmo = _REPLACEMENT_TMO_STANDARD 

263 # deliberately leave the "-p portal" arguments out, so that all the portals 

264 # always share the same config (esp. in corner case when switching from 

265 # mpath -> non-mpath, where we are only going to operate on one path). The 

266 # parameter could be useful if we want further flexibility in the future. 

267 cmd = ["iscsiadm", "-m", "node", "-T", targetIQN, # "-p", portal, 

268 "--op", "update", "-n", key, "-v"] 

269 fail_msg = "Failed to set replacement timeout" 

270 if mpath: 

271 # Only switch if the current config is a well-known non-mpath setting 

272 if current_tmo in [_REPLACEMENT_TMO_DEFAULT, _REPLACEMENT_TMO_STANDARD]: 

273 cmd.append(str(_REPLACEMENT_TMO_MPATH)) 

274 (stdout, stderr) = exn_on_failure(cmd, fail_msg) 

275 else: 

276 # the current_tmo is a customized value, no change 

277 util.SMlog("Keep the current replacement_timout value: %d." % current_tmo) 

278 else: 

279 # Only switch if the current config is a well-known mpath setting 

280 if current_tmo in [_REPLACEMENT_TMO_MPATH, _REPLACEMENT_TMO_STANDARD]: 

281 cmd.append(str(_REPLACEMENT_TMO_DEFAULT)) 

282 (stdout, stderr) = exn_on_failure(cmd, fail_msg) 

283 else: 

284 # the current_tmo is a customized value, no change 

285 util.SMlog("Keep the current replacement_timout value: %d." % current_tmo) 

286 

287 

288def get_current_initiator_name(): 

289 """Looks in the config file to see if we've already got a initiator name,  

290 returning it if so, or else returning None""" 

291 if os.path.exists(INITIATORNAME_FILE): 

292 try: 

293 f = open(INITIATORNAME_FILE, 'r') 

294 for line in f.readlines(): 

295 if line.strip().startswith("#"): 

296 continue 

297 if "InitiatorName" in line: 

298 IQN = line.split("=")[1] 

299 currentIQN = IQN.strip() 

300 f.close() 

301 return currentIQN 

302 f.close() 

303 except IOError as e: 

304 return None 

305 return None 

306 

307 

308def get_system_alias(): 

309 return socket.gethostname() 

310 

311 

312def set_current_initiator_name(localIQN): 

313 """Sets the initiator name in the config file. Raises an xs_error on error""" 

314 try: 

315 alias = get_system_alias() 

316 # MD3000i alias bug workaround 

317 if len(alias) > 30: 

318 alias = alias[0:30] 

319 f = open(INITIATORNAME_FILE, 'w') 

320 f.write('InitiatorName=%s\n' % localIQN) 

321 f.write('InitiatorAlias=%s\n' % alias) 

322 f.close() 

323 except IOError as e: 

324 raise xs_errors.XenError('ISCSIInitiator', \ 

325 opterr='Could not set initator name') 

326 

327 

328def login(portal, target, username, password, username_in="", password_in="", 

329 multipath=False): 

330 if username != "" and password != "": 

331 set_chap_settings(portal, target, username, password, username_in, password_in) 

332 else: 

333 remove_chap_settings(portal, target) 

334 

335 set_replacement_tmo(portal, target, multipath) 

336 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", target, "-l"] 

337 failuremessage = "Failed to login to target." 

338 try: 

339 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

340 except: 

341 raise xs_errors.XenError('ISCSILogin') 

342 

343 

344def logout(portal, target, all=False): 

345 if all: 

346 cmd = ["iscsiadm", "-m", "node", "-T", target, "-u"] 

347 else: 

348 cmd = ["iscsiadm", "-m", "node", "-p", portal, "-T", target, "-u"] 

349 failuremessage = "Failed to log out of target" 

350 try: 

351 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

352 except: 

353 raise xs_errors.XenError('ISCSILogout') 

354 

355 

356def delete(target): 

357 cmd = ["iscsiadm", "-m", "node", "-o", "delete", "-T", target] 

358 failuremessage = "Failed to delete target" 

359 try: 

360 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

361 except: 

362 raise xs_errors.XenError('ISCSIDelete') 

363 

364 

365def get_luns(targetIQN, portal): 

366 refresh_luns(targetIQN, portal) 

367 luns = [] 

368 path = os.path.join("/dev/iscsi", targetIQN, portal) 

369 try: 

370 for file in util.listdir(path): 

371 if file.find("LUN") == 0 and file.find("_") == -1: 

372 lun = file.replace("LUN", "") 

373 luns.append(lun) 

374 return luns 

375 except util.CommandException as inst: 

376 raise xs_errors.XenError('ISCSIDevice', opterr='Failed to find any LUNs') 

377 

378 

379def is_iscsi_daemon_running(): 

380 cmd = ["/usr/bin/systemctl", "is-active", "iscsid.service"] 

381 (rc, stdout, stderr) = util.doexec(cmd) 

382 return (rc == 0) 

383 

384 

385def stop_daemon(): 

386 if is_iscsi_daemon_running(): 

387 cmd = ["/usr/bin/systemctl", "stop", "iscsid.service"] 

388 failuremessage = "Failed to stop iscsi daemon" 

389 exn_on_failure(cmd, failuremessage) 

390 

391 

392def restart_daemon(): 

393 stop_daemon() 

394 if os.path.exists(os.path.join(_ISCSI_DB_PATH, 'nodes')): 394 ↛ 403line 394 didn't jump to line 403, because the condition on line 394 was never false

395 try: 

396 shutil.rmtree(os.path.join(_ISCSI_DB_PATH, 'nodes')) 

397 except: 

398 pass 

399 try: 

400 shutil.rmtree(os.path.join(_ISCSI_DB_PATH, 'send_targets')) 

401 except: 

402 pass 

403 cmd = ["/usr/bin/systemctl", "start", "iscsid.service"] 

404 failuremessage = "Failed to start iscsi daemon" 

405 exn_on_failure(cmd, failuremessage) 

406 

407 

408def wait_for_devs(targetIQN, portal): 

409 path = os.path.join("/dev/iscsi", targetIQN, portal) 

410 for i in range(0, 15): 

411 if os.path.exists(path): 

412 return True 

413 time.sleep(1) 

414 return False 

415 

416 

417def refresh_luns(targetIQN, portal): 

418 wait_for_devs(targetIQN, portal) 

419 try: 

420 path = os.path.join("/dev/iscsi", targetIQN, portal) 

421 id = scsiutil.getSessionID(path) 

422 f = open('/sys/class/scsi_host/host%s/scan' % id, 'w') 

423 f.write('- - -\n') 

424 f.close() 

425 time.sleep(2) # FIXME 

426 except: 

427 pass 

428 

429 

430def get_IQN_paths(): 

431 """Return the list of iSCSI session directories""" 

432 return glob.glob(_GENERIC_SESSION_PATH % '*') 

433 

434 

435def get_targetIQN(iscsi_host): 

436 """Get target IQN from sysfs for given iSCSI host number""" 

437 iqn_file = os.path.join(_GENERIC_SESSION_PATH % iscsi_host, 'targetname') 

438 targetIQN = util.get_single_entry(glob.glob(iqn_file)[0]) 

439 return targetIQN 

440 

441 

442def get_targetIP_and_port(iscsi_host): 

443 """Get target IP address and port for given iSCSI host number""" 

444 connection_dir = _GENERIC_CONNECTION_PATH % iscsi_host 

445 ip = util.get_single_entry(glob.glob(os.path.join( 

446 connection_dir, 'persistent_address'))[0]) 

447 port = util.get_single_entry(glob.glob(os.path.join( 

448 connection_dir, 'persistent_port'))[0]) 

449 return (ip, port) 

450 

451 

452def get_path(targetIQN, portal, lun): 

453 """Gets the path of a specified LUN - this should be e.g. '1' or '5'""" 

454 path = os.path.join("/dev/iscsi", targetIQN, portal) 

455 return os.path.join(path, "LUN" + lun) 

456 

457 

458def get_path_safe(targetIQN, portal, lun): 

459 """Gets the path of a specified LUN, and ensures that it exists. 

460 Raises an exception if it hasn't appeared after the timeout""" 

461 path = get_path(targetIQN, portal, lun) 

462 for i in range(0, 15): 

463 if os.path.exists(path): 

464 return path 

465 time.sleep(1) 

466 raise xs_errors.XenError('ISCSIDevice', \ 

467 opterr='LUN failed to appear at path %s' % path) 

468 

469 

470def match_target(tgt, s): 

471 regex = re.compile(tgt) 

472 return regex.search(s, 0) 

473 

474 

475def match_targetIQN(tgtIQN, s): 

476 if not len(s): 

477 return False 

478 if tgtIQN == "any": 

479 return True 

480 # Extract IQN from iscsiadm -m session 

481 # Ex: tcp: [17] 10.220.98.9:3260,1 iqn.2009-01.xenrt.test:iscsi4181a93e 

482 siqn = s.split(",")[1].split()[1].strip() 

483 return (siqn == tgtIQN) 

484 

485 

486def match_session(s): 

487 regex = re.compile("^tcp:") 

488 return regex.search(s, 0) 

489 

490 

491def _compare_sessions_to_tgt(session_output, tgtIQN, tgt=''): 

492 for line in session_output.split('\n'): 

493 if match_targetIQN(tgtIQN, line) and match_session(line): 

494 if len(tgt): 494 ↛ 498line 494 didn't jump to line 498, because the condition on line 494 was never false

495 if match_target(tgt, line): 

496 return True 

497 else: 

498 return True 

499 return False 

500 

501 

502def _checkTGT(tgtIQN, tgt=''): 

503 if not is_iscsi_daemon_running(): 

504 return False 

505 failuremessage = "Failure occured querying iscsi daemon" 

506 cmd = ["iscsiadm", "-m", "session"] 

507 try: 

508 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

509 # Recent versions of iscsiadm return error it this list is empty. 

510 # Quick and dirty handling 

511 except Exception as e: 

512 util.SMlog("%s failed with %s" % (cmd, e.args)) 

513 stdout = "" 

514 return _compare_sessions_to_tgt(stdout, tgtIQN, tgt) 

515 

516 

517def get_rootdisk_IQNs(): 

518 """Return the list of IQNs for targets required by root filesystem""" 

519 if not os.path.isdir('/sys/firmware/ibft/'): 519 ↛ 521line 519 didn't jump to line 521, because the condition on line 519 was never false

520 return [] 

521 dirs = [x for x in os.listdir('/sys/firmware/ibft/') if x.startswith('target')] 

522 return [open('/sys/firmware/ibft/%s/target-name' % d).read().strip() for d in dirs] 

523 

524 

525def _checkAnyTGT(): 

526 if not is_iscsi_daemon_running(): 

527 return False 

528 rootIQNs = get_rootdisk_IQNs() 

529 failuremessage = "Failure occured querying iscsi daemon" 

530 cmd = ["iscsiadm", "-m", "session"] 

531 try: 

532 (stdout, stderr) = exn_on_failure(cmd, failuremessage) 

533 # Recent versions of iscsiadm return error it this list is empty. 

534 # Quick and dirty handling 

535 except Exception as e: 

536 util.SMlog("%s failed with %s" % (cmd, e.args)) 

537 stdout = "" 

538 for session in filter(match_session, stdout.split('\n')): 

539 iqn = session.split()[-1] 

540 if not iqn in rootIQNs: 

541 return True 

542 return False 

543 

544 

545def ensure_daemon_running_ok(localiqn): 

546 """Check that the daemon is running and the initiator name is correct""" 

547 if not is_iscsi_daemon_running(): 

548 set_current_initiator_name(localiqn) 

549 restart_daemon() 

550 else: 

551 currentiqn = get_current_initiator_name() 

552 if currentiqn != localiqn: 

553 if _checkAnyTGT(): 

554 raise xs_errors.XenError('ISCSIInitiator', \ 

555 opterr='Daemon already running with ' \ 

556 + 'target(s) attached using ' \ 

557 + 'different IQN') 

558 set_current_initiator_name(localiqn) 

559 restart_daemon() 

560 

561 

562def get_iscsi_interfaces(): 

563 result = [] 

564 try: 

565 # Get all configured iscsiadm interfaces 

566 cmd = ["iscsiadm", "-m", "iface"] 

567 (stdout, stderr) = exn_on_failure(cmd, 

568 "Failure occured querying iscsi daemon") 

569 # Get the interface (first column) from a line such as default 

570 # tcp,<empty>,<empty>,<empty>,<empty> 

571 for line in stdout.split("\n"): 

572 line_element = line.split(" ") 

573 interface_name = line_element[0] 

574 # ignore interfaces which aren't marked as starting with 

575 # c_. 

576 if len(line_element) == 2 and interface_name[:2] == "c_": 

577 result.append(interface_name) 

578 except: 

579 # Ignore exception from exn on failure, still return the default 

580 # interface 

581 pass 

582 # In case there are no configured interfaces, still add the default 

583 # interface 

584 if len(result) == 0: 

585 result.append("default") 

586 return result