Coverage for drivers/LVHDoISCSISR.py : 14%

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#
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
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"]
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)']]
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 }
71class LVHDoISCSISR(LVHDSR.LVHDSR):
72 """LVHD over ISCSI storage repository"""
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)
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()
91 # If this is a vdi command, don't initialise SR
92 if util.isVDICommand(self.original_srcmd.cmd): 92 ↛ 93line 92 didn't jump to line 93, because the condition on line 92 was never true
93 self.SCSIid = self.dconf['SCSIid']
94 else:
95 if 'target' in self.original_srcmd.dconf: 95 ↛ 97line 95 didn't jump to line 97, because the condition on line 95 was never false
96 self.original_srcmd.dconf['targetlist'] = self.original_srcmd.dconf['target']
97 iscsi = BaseISCSI.BaseISCSISR(self.original_srcmd, sr_uuid)
98 self.iscsiSRs = []
99 self.iscsiSRs.append(iscsi)
101 saved_exc = None
102 if self.dconf['target'].find(',') == 0 or self.dconf['targetIQN'] == "*": 102 ↛ 173line 102 didn't jump to line 173, because the condition on line 102 was never false
103 # Instantiate multiple sessions
104 self.iscsiSRs = []
105 if self.dconf['targetIQN'] == "*": 105 ↛ 108line 105 didn't jump to line 108, because the condition on line 105 was never false
106 IQN = "any"
107 else:
108 IQN = self.dconf['targetIQN']
109 dict = {}
110 IQNstring = ""
111 IQNs = []
112 try:
113 if 'multiSession' in self.dconf: 113 ↛ 114line 113 didn't jump to line 114, because the condition on line 113 was never true
114 IQNs = self.dconf['multiSession'].split("|")
115 for IQN in IQNs:
116 if IQN:
117 dict[IQN] = ""
118 else:
119 try:
120 IQNs.remove(IQN)
121 except:
122 # Exceptions are not expected but just in case
123 pass
124 # Order in multiSession must be preserved. It is important for dual-controllers.
125 # IQNstring cannot be built with a dictionary iteration because of this
126 IQNstring = self.dconf['multiSession']
127 else:
128 for tgt in self.dconf['target'].split(','): 128 ↛ 147line 128 didn't jump to line 147, because the loop on line 128 didn't complete
129 try:
130 tgt_ip = util._convertDNS(tgt)
131 except:
132 raise xs_errors.XenError('DNSError')
133 iscsilib.ensure_daemon_running_ok(iscsi.localIQN)
134 map = iscsilib.discovery(tgt_ip, iscsi.port, iscsi.chapuser, iscsi.chappassword, targetIQN=IQN)
135 util.SMlog("Discovery for IP %s returned %s" % (tgt, map))
136 for i in range(0, len(map)):
137 (portal, tpgt, iqn) = map[i]
138 (ipaddr, port) = iscsilib.parse_IP_port(portal)
139 try:
140 util._testHost(ipaddr, int(port), 'ISCSITarget')
141 except:
142 util.SMlog("Target Not reachable: (%s:%s)" % (ipaddr, port))
143 continue
144 key = "%s,%s,%s" % (ipaddr, port, iqn)
145 dict[key] = ""
146 # Again, do not mess up with IQNs order. Dual controllers will benefit from that
147 if IQNstring == "":
148 # Compose the IQNstring first
149 for key in dict.keys():
150 IQNstring += "%s|" % key
151 # Reinitialize and store iterator
152 key_iterator = iter(dict.keys())
153 else:
154 key_iterator = IQNs
156 # Now load the individual iSCSI base classes
157 for key in key_iterator:
158 (ipaddr, port, iqn) = key.split(',')
159 srcmd_copy = copy.deepcopy(self.original_srcmd)
160 srcmd_copy.dconf['target'] = ipaddr
161 srcmd_copy.dconf['targetIQN'] = iqn
162 srcmd_copy.dconf['multiSession'] = IQNstring
163 util.SMlog("Setting targetlist: %s" % srcmd_copy.dconf['targetlist'])
164 self.iscsiSRs.append(BaseISCSI.BaseISCSISR(srcmd_copy, sr_uuid))
165 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
166 if pbd is not None and 'multiSession' not in self.dconf:
167 dconf = self.session.xenapi.PBD.get_device_config(pbd)
168 dconf['multiSession'] = IQNstring
169 self.session.xenapi.PBD.set_device_config(pbd, dconf)
170 except Exception as exc:
171 util.logException("LVHDoISCSISR.load")
172 saved_exc = exc
173 try:
174 self.iscsi = self.iscsiSRs[0]
175 except IndexError as exc:
176 if isinstance(saved_exc, SR.SROSError):
177 raise saved_exc # pylint: disable-msg=E0702
178 elif isinstance(saved_exc, Exception): 178 ↛ 181line 178 didn't jump to line 181, because the condition on line 178 was never false
179 raise xs_errors.XenError('SMGeneral', str(saved_exc))
180 else:
181 raise xs_errors.XenError('SMGeneral', str(exc))
183 # Be extremely careful not to throw exceptions here since this function
184 # is the main one used by all operations including probing and creating
185 pbd = None
186 try:
187 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
188 except:
189 pass
191 # Apart from the upgrade case, user must specify a SCSIid
192 if 'SCSIid' not in self.dconf:
193 # Dual controller issue
194 self.LUNs = {} # Dict for LUNs from all the iscsi objects
195 for ii in range(0, len(self.iscsiSRs)):
196 self.iscsi = self.iscsiSRs[ii]
197 self._LUNprint(sr_uuid)
198 for key in self.iscsi.LUNs:
199 self.LUNs[key] = self.iscsi.LUNs[key]
200 self.print_LUNs_XML()
201 self.iscsi = self.iscsiSRs[0] # back to original value
202 raise xs_errors.XenError('ConfigSCSIid')
204 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:
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')
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')
341 LVHDSR.LVHDSR.load(self, sr_uuid)
343 def print_LUNs_XML(self):
344 dom = xml.dom.minidom.Document()
345 element = dom.createElement("iscsi-target")
346 dom.appendChild(element)
347 for uuid in self.LUNs:
348 val = self.LUNs[uuid]
349 entry = dom.createElement('LUN')
350 element.appendChild(entry)
352 for attr in ('vendor', 'serial', 'LUNid', \
353 'size', 'SCSIid'):
354 try:
355 aval = getattr(val, attr)
356 except AttributeError:
357 continue
359 if aval:
360 subentry = dom.createElement(attr)
361 entry.appendChild(subentry)
362 textnode = dom.createTextNode(str(aval))
363 subentry.appendChild(textnode)
365 print(dom.toprettyxml(), file=sys.stderr)
367 def _getSCSIid_from_LUN(self, sr_uuid):
368 was_attached = True
369 self.iscsi.attach(sr_uuid)
370 dev = self.dconf['LUNid'].split(',')
371 if len(dev) > 1:
372 raise xs_errors.XenError('LVMOneLUN')
373 path = os.path.join(self.iscsi.path, "LUN%s" % dev[0])
374 if not util.wait_for_path(path, BaseISCSI.MAX_TIMEOUT):
375 util.SMlog("Unable to detect LUN attached to host [%s]" % path)
376 try:
377 SCSIid = scsiutil.getSCSIid(path)
378 except:
379 raise xs_errors.XenError('InvalidDev')
380 self.iscsi.detach(sr_uuid)
381 return SCSIid
383 def _LUNprint(self, sr_uuid):
384 if self.iscsi.attached:
385 # Force a rescan on the bus.
386 self.iscsi.refresh()
387# time.sleep(5)
388# Now call attach (handles the refcounting + session activa)
389 self.iscsi.attach(sr_uuid)
391 util.SMlog("LUNprint: waiting for path: %s" % self.iscsi.path)
392 if util.wait_for_path("%s/LUN*" % self.iscsi.path, BaseISCSI.MAX_TIMEOUT):
393 try:
394 adapter = self.iscsi.adapter[self.iscsi.address]
395 util.SMlog("adapter=%s" % adapter)
397 # find a scsi device on which to issue a report luns command:
398 devs = glob.glob("%s/LUN*" % self.iscsi.path)
399 sgdevs = []
400 for i in devs:
401 sgdevs.append(int(i.split("LUN")[1]))
402 sgdevs.sort()
403 sgdev = "%s/LUN%d" % (self.iscsi.path, sgdevs[0])
405 # issue a report luns:
406 luns = util.pread2(["/usr/bin/sg_luns", "-q", sgdev]).split('\n')
407 nluns = len(luns) - 1 # remove the line relating to the final \n
408 # check if the LUNs are MPP-RDAC Luns
409 scsi_id = scsiutil.getSCSIid(sgdev)
411 # make sure we've got that many sg devices present
412 for i in range(0, 30):
413 luns = scsiutil._dosgscan()
414 sgdevs = [r for r in luns if r[1] == adapter]
415 if len(sgdevs) >= nluns:
416 util.SMlog("Got all %d sg devices" % nluns)
417 break
418 else:
419 util.SMlog("Got %d sg devices - expecting %d" % (len(sgdevs), nluns))
420 time.sleep(1)
422 if os.path.exists("/sbin/udevsettle"):
423 util.pread2(["/sbin/udevsettle"])
424 else:
425 util.pread2(["/sbin/udevadm", "settle"])
426 except:
427 util.SMlog("Generic exception caught. Pass")
428 pass # Make sure we don't break the probe...
430 self.iscsi.print_LUNs()
431 self.iscsi.detach(sr_uuid)
433 def create(self, sr_uuid, size):
434 # Check SCSIid not already in use by other PBDs
435 if util.test_SCSIid(self.session, sr_uuid, self.SCSIid):
436 raise xs_errors.XenError('SRInUse')
438 self.iscsi.attach(sr_uuid)
439 try:
440 if not self.iscsi._attach_LUN_bySCSIid(self.SCSIid):
441 # UPGRADE FROM GEORGE: take care of ill-formed SCSIid
442 upgraded = False
443 matchSCSIid = False
444 for file in filter(self.iscsi.match_lun, util.listdir(self.iscsi.path)):
445 path = os.path.join(self.iscsi.path, file)
446 if not util.wait_for_path(path, BaseISCSI.MAX_TIMEOUT):
447 util.SMlog("Unable to detect LUN attached to host [%s]" % path)
448 continue
449 try:
450 SCSIid = scsiutil.getSCSIid(path)
451 except:
452 continue
453 try:
454 matchSCSIid = scsiutil.compareSCSIid_2_6_18(self.SCSIid, path)
455 except:
456 continue
457 if (matchSCSIid):
458 util.SMlog("Performing upgrade from George")
459 try:
460 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
461 device_config = self.session.xenapi.PBD.get_device_config(pbd)
462 device_config['SCSIid'] = SCSIid
463 self.session.xenapi.PBD.set_device_config(pbd, device_config)
465 self.dconf['SCSIid'] = SCSIid
466 self.SCSIid = self.dconf['SCSIid']
467 except:
468 continue
469 if not self.iscsi._attach_LUN_bySCSIid(self.SCSIid):
470 raise xs_errors.XenError('InvalidDev')
471 else:
472 upgraded = True
473 break
474 else:
475 util.SMlog("Not a matching LUN, skip ... scsi_id is: %s" % SCSIid)
476 continue
477 if not upgraded:
478 raise xs_errors.XenError('InvalidDev')
479 self._pathrefresh(LVHDoISCSISR)
480 LVHDSR.LVHDSR.create(self, sr_uuid, size)
481 except Exception as inst:
482 self.iscsi.detach(sr_uuid)
483 raise xs_errors.XenError("SRUnavailable", opterr=inst)
484 self.iscsi.detach(sr_uuid)
486 def delete(self, sr_uuid):
487 self._pathrefresh(LVHDoISCSISR)
488 LVHDSR.LVHDSR.delete(self, sr_uuid)
489 for i in self.iscsiSRs:
490 i.detach(sr_uuid)
492 def attach(self, sr_uuid):
493 try:
494 connected = False
495 for i in self.iscsiSRs:
496 try:
497 i.attach(sr_uuid)
498 except SR.SROSError as inst:
499 # Some iscsi objects can fail login but not all. Storing exception
500 if inst.errno == 141:
501 util.SMlog("Connection failed for target %s, continuing.." % i.target)
502 stored_exception = inst
503 continue
504 else:
505 raise
506 else:
507 connected = True
509 if not i._attach_LUN_bySCSIid(self.SCSIid):
510 raise xs_errors.XenError('InvalidDev')
512 # Check if at least one iscsi succeeded
513 if not connected:
514 raise stored_exception
516 if 'multiSession' in self.dconf:
517 # Force a manual bus refresh
518 for a in self.iscsi.adapter:
519 scsiutil.rescan([self.iscsi.adapter[a]])
521 self._pathrefresh(LVHDoISCSISR)
522 LVHDSR.LVHDSR.attach(self, sr_uuid)
523 except Exception as inst:
524 for i in self.iscsiSRs:
525 i.detach(sr_uuid)
526 raise xs_errors.XenError("SRUnavailable", opterr=inst)
527 self._setMultipathableFlag(SCSIid=self.SCSIid)
529 def detach(self, sr_uuid):
530 LVHDSR.LVHDSR.detach(self, sr_uuid)
531 for i in self.iscsiSRs:
532 i.detach(sr_uuid)
534 def scan(self, sr_uuid):
535 self._pathrefresh(LVHDoISCSISR)
536 if self.mpath == "true":
537 for i in self.iscsiSRs:
538 try:
539 i.attach(sr_uuid)
540 except SR.SROSError:
541 util.SMlog("Connection failed for target %s, continuing.." % i.target)
542 LVHDSR.LVHDSR.scan(self, sr_uuid)
544 def probe(self):
545 self.uuid = util.gen_uuid()
547 # When multipathing is enabled, since we don't refcount the multipath maps,
548 # we should not attempt to do the iscsi.attach/detach when the map is already present,
549 # as this will remove it (which may well be in use).
550 if self.mpath == 'true' and 'SCSIid' in self.dconf:
551 maps = []
552 try:
553 maps = mpath_cli.list_maps()
554 except:
555 pass
557 if self.dconf['SCSIid'] in maps:
558 raise xs_errors.XenError('SRInUse')
560 self.iscsi.attach(self.uuid)
561 if not self.iscsi._attach_LUN_bySCSIid(self.SCSIid):
562 util.SMlog("Unable to detect LUN")
563 raise xs_errors.XenError('InvalidDev')
564 self._pathrefresh(LVHDoISCSISR)
565 out = LVHDSR.LVHDSR.probe(self)
566 self.iscsi.detach(self.uuid)
567 return out
569 def vdi(self, uuid):
570 return LVHDoISCSIVDI(self, uuid)
573class LVHDoISCSIVDI(LVHDSR.LVHDVDI):
574 def generate_config(self, sr_uuid, vdi_uuid):
575 util.SMlog("LVHDoISCSIVDI.generate_config")
576 if not lvutil._checkLV(self.path):
577 raise xs_errors.XenError('VDIUnavailable')
578 dict = {}
579 self.sr.dconf['localIQN'] = self.sr.iscsi.localIQN
580 self.sr.dconf['multipathing'] = self.sr.mpath
581 self.sr.dconf['multipathhandle'] = self.sr.mpathhandle
582 dict['device_config'] = self.sr.dconf
583 if 'chappassword_secret' in dict['device_config']:
584 s = util.get_secret(self.session, dict['device_config']['chappassword_secret'])
585 del dict['device_config']['chappassword_secret']
586 dict['device_config']['chappassword'] = s
587 dict['sr_uuid'] = sr_uuid
588 dict['vdi_uuid'] = vdi_uuid
589 dict['command'] = 'vdi_attach_from_config'
590 # Return the 'config' encoded within a normal XMLRPC response so that
591 # we can use the regular response/error parsing code.
592 config = xmlrpc.client.dumps(tuple([dict]), "vdi_attach_from_config")
593 return xmlrpc.client.dumps((config, ), "", True)
595 def attach_from_config(self, sr_uuid, vdi_uuid):
596 util.SMlog("LVHDoISCSIVDI.attach_from_config")
597 try:
598 self.sr.iscsi.attach(sr_uuid)
599 if not self.sr.iscsi._attach_LUN_bySCSIid(self.sr.SCSIid):
600 raise xs_errors.XenError('InvalidDev')
601 return LVHDSR.LVHDVDI.attach(self, sr_uuid, vdi_uuid)
602 except:
603 util.logException("LVHDoISCSIVDI.attach_from_config")
604 raise xs_errors.XenError('SRUnavailable', \
605 opterr='Unable to attach the heartbeat disk')
608if __name__ == '__main__': 608 ↛ 609line 608 didn't jump to line 609, because the condition on line 608 was never true
609 SRCommand.run(LVHDoISCSISR, DRIVER_INFO)
610else:
611 SR.registerSR(LVHDoISCSISR)