Coverage for libs/sm/core/iscsi.py: 34%

372 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2026-07-10 07:59 +0000

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 

18from sm.core import util 

19import os 

20from sm.core import scsiutil 

21import time 

22import socket 

23import re 

24import shutil 

25from sm.core import xs_errors 

26from sm.core import 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 rescan_target(portal, target): 

134 """ 

135 Rescan the given iscsi portal and target 

136 (used by the sm-core-libs compatibility layer) 

137 """ 

138 sessions_cmd = ["iscsiadm", "-m", "session"] 

139 failure_message = "Failed to read iscsi sessions" 

140 (stdout, _) = exn_on_failure(sessions_cmd, failure_message) 

141 

142 session_re = r"^[^\[]*\[(\d+)\] " + portal + r",\d+ " + target 

143 

144 for line in stdout.splitlines(): 

145 session_match = re.match(session_re, line) 

146 if session_match: 

147 session_id = session_match.group(1) 

148 rescan_cmd = ["iscsiadm", "-m", "session", '-r', session_id, '--rescan'] 

149 (_, _) = exn_on_failure(rescan_cmd, "Failed to rescan session") 

150 

151 

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

153 interface_array=["default"]): 

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

155 TargetIQNs available on the specified target and port. Returns 

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

157 group tag) and the target name""" 

158 

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

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

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

162 

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

164 tmpdirname = tempfile.mkdtemp() 

165 try: 

166 save_rootdisk_nodes(tmpdirname) 

167 

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

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

170 else: 

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

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

173 for interface in interface_array: 

174 cmd_base.append("-I") 

175 cmd_base.append(interface) 

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

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

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

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

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

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

182 "username/password (if applicable)" 

183 try: 

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

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

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

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

188 else: 

189 cmd = cmd_disc 

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

191 except: 

192 raise xs_errors.XenError('ISCSILogin') 

193 finally: 

194 restore_rootdisk_nodes(tmpdirname) 

195 finally: 

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

197 

198 return parse_node_output(stdout, targetIQN) 

199 

200 

201def get_node_records(targetIQN="any"): 

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

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

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

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

206 return parse_node_output(stdout, targetIQN) 

207 

208 

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

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

211 portal/targetIQN combination""" 

212 failuremessage = "Failed to set CHAP settings" 

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

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

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

216 

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

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

219 username] 

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

221 

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

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

224 password] 

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

226 

227 if (username_in != ""): 

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

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

230 username_in] 

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

232 

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

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

235 password_in] 

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

237 

238 

239def remove_chap_settings(portal, targetIQN): 

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

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

242 (stdout, stderr) = noexn_on_failure(cmd) 

243 

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

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

246 (stdout, stderr) = noexn_on_failure(cmd) 

247 

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

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

250 (stdout, stderr) = noexn_on_failure(cmd) 

251 

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

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

254 (stdout, stderr) = noexn_on_failure(cmd) 

255 

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

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

258 (stdout, stderr) = noexn_on_failure(cmd) 

259 

260 

261def get_node_config (portal, targetIQN): 

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

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

264 failuremessage = "Failed to get node configurations" 

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

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

267 ini_sec = "root" 

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

269 parser = RawConfigParser() 

270 parser.read_file(str_fp) 

271 str_fp.close() 

272 return dict(parser.items(ini_sec)) 

273 

274 

275def set_replacement_tmo (portal, targetIQN, mpath): 

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

277 try: 

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

279 except: 

280 # Assume a standard TMO setting if get_node_config fails 

281 current_tmo = _REPLACEMENT_TMO_STANDARD 

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

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

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

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

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

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

288 fail_msg = "Failed to set replacement timeout" 

289 if mpath: 

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

291 if current_tmo in [_REPLACEMENT_TMO_DEFAULT, _REPLACEMENT_TMO_STANDARD]: 

292 cmd.append(str(_REPLACEMENT_TMO_MPATH)) 

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

294 else: 

295 # the current_tmo is a customized value, no change 

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

297 else: 

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

299 if current_tmo in [_REPLACEMENT_TMO_MPATH, _REPLACEMENT_TMO_STANDARD]: 

300 cmd.append(str(_REPLACEMENT_TMO_DEFAULT)) 

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

302 else: 

303 # the current_tmo is a customized value, no change 

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

305 

306 

307def get_current_initiator_name(): 

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

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

310 if os.path.exists(INITIATORNAME_FILE): 

311 try: 

312 f = open(INITIATORNAME_FILE, 'r') 

313 for line in f.readlines(): 

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

315 continue 

316 if "InitiatorName" in line: 

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

318 currentIQN = IQN.strip() 

319 f.close() 

320 return currentIQN 

321 f.close() 

322 except IOError as e: 

323 return None 

324 return None 

325 

326 

327def get_system_alias(): 

328 return socket.gethostname() 

329 

330 

331def set_current_initiator_name(localIQN): 

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

333 try: 

334 alias = get_system_alias() 

335 # MD3000i alias bug workaround 

336 if len(alias) > 30: 

337 alias = alias[0:30] 

338 f = open(INITIATORNAME_FILE, 'w') 

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

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

341 f.close() 

342 except IOError as e: 

343 raise xs_errors.XenError('ISCSIInitiator', \ 

344 opterr='Could not set initator name') 

345 

346 

347def get_portal_target_ref(portal, target): 

348 return '{}#{}'.format(portal, target) 

349 

350 

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

352 multipath=False): 

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

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

355 else: 

356 remove_chap_settings(portal, target) 

357 

358 set_replacement_tmo(portal, target, multipath) 

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

360 failuremessage = "Failed to login to target." 

361 try: 

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

363 except: 

364 raise xs_errors.XenError('ISCSILogin') 

365 

366 

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

368 if all: 

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

370 else: 

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

372 failuremessage = "Failed to log out of target" 

373 try: 

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

375 except: 

376 raise xs_errors.XenError('ISCSILogout') 

377 

378 

379def delete(target): 

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

381 failuremessage = "Failed to delete target" 

382 try: 

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

384 except: 

385 raise xs_errors.XenError('ISCSIDelete') 

386 

387 

388def get_luns(targetIQN, portal): 

389 refresh_luns(targetIQN, portal) 

390 luns = [] 

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

392 try: 

393 for file in util.listdir(path): 

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

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

396 luns.append(lun) 

397 return luns 

398 except util.CommandException as inst: 

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

400 

401 

402def is_iscsi_daemon_running(): 

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

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

405 return (rc == 0) 

406 

407 

408def stop_daemon(): 

409 if is_iscsi_daemon_running(): 

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

411 failuremessage = "Failed to stop iscsi daemon" 

412 exn_on_failure(cmd, failuremessage) 

413 

414 

415def restart_daemon(): 

416 stop_daemon() 

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

418 try: 

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

420 except: 

421 pass 

422 try: 

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

424 except: 

425 pass 

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

427 failuremessage = "Failed to start iscsi daemon" 

428 exn_on_failure(cmd, failuremessage) 

429 

430 

431def wait_for_devs(targetIQN, portal): 

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

433 for i in range(0, 15): 

434 if os.path.exists(path): 

435 return True 

436 time.sleep(1) 

437 return False 

438 

439 

440def refresh_luns(targetIQN, portal): 

441 wait_for_devs(targetIQN, portal) 

442 try: 

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

444 id = scsiutil.getSessionID(path) 

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

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

447 f.close() 

448 time.sleep(2) # FIXME 

449 except: 

450 pass 

451 

452 

453def get_IQN_paths(): 

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

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

456 

457 

458def get_targetIQN(iscsi_host): 

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

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

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

462 return targetIQN 

463 

464 

465def get_targetIP_and_port(iscsi_host): 

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

467 connection_dir = _GENERIC_CONNECTION_PATH % iscsi_host 

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

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

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

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

472 return (ip, port) 

473 

474 

475def get_path(targetIQN, portal, lun): 

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

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

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

479 

480 

481def get_path_safe(targetIQN, portal, lun): 

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

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

484 path = get_path(targetIQN, portal, lun) 

485 for i in range(0, 15): 

486 if os.path.exists(path): 

487 return path 

488 time.sleep(1) 

489 raise xs_errors.XenError('ISCSIDevice', \ 

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

491 

492 

493def match_target(tgt, s): 

494 regex = re.compile(tgt) 

495 return regex.search(s, 0) 

496 

497 

498def match_targetIQN(tgtIQN, s): 

499 if not len(s): 

500 return False 

501 if tgtIQN == "any": 

502 return True 

503 # Extract IQN from iscsiadm -m session 

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

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

506 return (siqn == tgtIQN) 

507 

508 

509def match_session(s): 

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

511 return regex.search(s, 0) 

512 

513 

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

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

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

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

518 if match_target(tgt, line): 

519 return True 

520 else: 

521 return True 

522 return False 

523 

524 

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

526 if not is_iscsi_daemon_running(): 

527 return False 

528 failuremessage = "Failure occured querying iscsi daemon" 

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

530 try: 

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

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

533 # Quick and dirty handling 

534 except Exception as e: 

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

536 stdout = "" 

537 return _compare_sessions_to_tgt(stdout, tgtIQN, tgt) 

538 

539 

540def get_rootdisk_IQNs(): 

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

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

543 return [] 

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

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

546 

547 

548def _checkAnyTGT(): 

549 if not is_iscsi_daemon_running(): 

550 return False 

551 rootIQNs = get_rootdisk_IQNs() 

552 failuremessage = "Failure occured querying iscsi daemon" 

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

554 try: 

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

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

557 # Quick and dirty handling 

558 except Exception as e: 

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

560 stdout = "" 

561 for e in filter(match_session, stdout.split('\n')): 

562 iqn = e.split()[-1] 

563 if not iqn in rootIQNs: 

564 return True 

565 return False 

566 

567 

568def ensure_daemon_running_ok(localiqn): 

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

570 if not is_iscsi_daemon_running(): 

571 set_current_initiator_name(localiqn) 

572 restart_daemon() 

573 else: 

574 currentiqn = get_current_initiator_name() 

575 if currentiqn != localiqn: 

576 if _checkAnyTGT(): 

577 raise xs_errors.XenError('ISCSIInitiator', \ 

578 opterr='Daemon already running with ' \ 

579 + 'target(s) attached using ' \ 

580 + 'different IQN') 

581 set_current_initiator_name(localiqn) 

582 restart_daemon() 

583 

584 

585def get_iscsi_interfaces(): 

586 result = [] 

587 try: 

588 # Get all configured iscsiadm interfaces 

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

590 (stdout, stderr) = exn_on_failure(cmd, 

591 "Failure occured querying iscsi daemon") 

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

593 # tcp,<empty>,<empty>,<empty>,<empty> 

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

595 line_element = line.split(" ") 

596 interface_name = line_element[0] 

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

598 # c_. 

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

600 result.append(interface_name) 

601 except: 

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

603 # interface 

604 pass 

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

606 # interface 

607 if len(result) == 0: 

608 result.append("default") 

609 return result