Coverage for drivers/ISOSR.py : 37%

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# ISOSR: remote iso storage repository
20import SR
21import VDI
22import SRCommand
23import util
24import nfs
25import os
26import re
27import xs_errors
28import cifutils
30CAPABILITIES = ["VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH",
31 "SR_SCAN", "SR_ATTACH", "SR_DETACH"]
33CONFIGURATION = \
34 [['location', 'path to mount (required) (e.g. server:/path)'],
35 ['options',
36 'extra options to pass to mount (deprecated) (e.g. \'-o ro\')'],
37 ['type', 'cifs or nfs'],
38 nfs.NFS_VERSION]
40DRIVER_INFO = {
41 'name': 'ISO',
42 'description': 'Handles CD images stored as files in iso format',
43 'vendor': 'Citrix Systems Inc',
44 'copyright': '(C) 2008 Citrix Systems Inc',
45 'driver_version': '1.0',
46 'required_api_version': '1.0',
47 'capabilities': CAPABILITIES,
48 'configuration': CONFIGURATION
49 }
51TYPE = "iso"
52SMB_VERSION_1 = '1.0'
53SMB_VERSION_3 = '3.0'
54NFSPORT = 2049
57def is_image_utf8_compatible(s):
58 # pylint: disable=no-member
59 regex = re.compile("\.iso$|\.img$", re.I)
60 if regex.search(s) is None:
61 return False
63 # Check for extended characters
64 if type(s) == str:
65 try:
66 s.encode('utf-8')
67 except UnicodeEncodeError as e:
68 util.SMlog("WARNING: This string is not UTF-8 compatible.")
69 return False
70 return True
73def tools_iso_name(filename):
74 # The tools ISO used have a "xs-" prefix in its name.
75 # We recognise both and set the name_label accordingly.
76 if filename[:3] == "xs-":
77 return "xs-tools.iso"
78 else:
79 return "guest-tools.iso"
82class ISOSR(SR.SR):
83 """Local file storage repository"""
85 # Some helper functions:
86 def _checkmount(self):
87 """Checks that the mountpoint exists and is mounted"""
88 if not util.pathexists(self.mountpoint): 88 ↛ 90line 88 didn't jump to line 90, because the condition on line 88 was never false
89 return False
90 try:
91 ismount = util.ismount(self.mountpoint)
92 except util.CommandException as inst:
93 return False
94 return ismount
96 def _checkTargetStr(self, location):
97 if 'type' not in self.dconf:
98 return
99 if self.dconf['type'] == 'cifs': 99 ↛ 100line 99 didn't jump to line 100, because the condition on line 99 was never true
100 tgt = ''
101 if re.search('^//', location):
102 tgt = location.split('/')[2]
103 elif re.search(r'^\\', location):
104 l = location.split('\\')
105 for i in location.split('\\'):
106 if i:
107 tgt = i
108 break
109 if not tgt:
110 raise xs_errors.XenError('ISOLocationStringError')
111 else:
112 if location.find(':') == -1: 112 ↛ 113line 112 didn't jump to line 113, because the condition on line 112 was never true
113 raise xs_errors.XenError('ISOLocationStringError')
114 tgt = location.split(':')[0]
116 try:
117 util._convertDNS(tgt)
118 except:
119 raise xs_errors.XenError('DNSError')
121 # pylint: disable=no-member
122 uuid_file_regex = re.compile(
123 "([0-9a-f]{8}-(([0-9a-f]{4})-){3}[0-9a-f]{12})\.(iso|img)", re.I)
125 def _loadvdis(self):
126 """Scan the directory and get uuids either from the VDI filename, \
127 or by creating a new one."""
128 if self.vdis:
129 return
131 for name in filter(is_image_utf8_compatible,
132 util.listdir(self.path, quiet=True)):
133 fileName = self.path + "/" + name
134 if os.path.isdir(fileName):
135 util.SMlog("_loadvdis : %s is a directory. Ignore" % fileName)
136 continue
138 # CA-80254: Check for iso/img files whose name consists of extended
139 # characters.
140 try:
141 name.encode('ascii')
142 except UnicodeEncodeError:
143 raise xs_errors.XenError('CIFSExtendedCharsNotSupported', \
144 opterr='The repository contains at least one file whose name consists of extended characters.')
146 self.vdis[name] = ISOVDI(self, name)
147 # Set the VDI UUID if the filename is of the correct form.
148 # Otherwise, one will be generated later in VDI._db_introduce.
149 m = self.uuid_file_regex.match(name)
150 if m:
151 self.vdis[name].uuid = m.group(1)
153 # Synchronise the read-only status with existing VDI records
154 __xenapi_records = util.list_VDI_records_in_sr(self)
155 __xenapi_locations = {}
156 for vdi in __xenapi_records.keys():
157 __xenapi_locations[__xenapi_records[vdi]['location']] = vdi
158 for vdi in self.vdis.values():
159 if vdi.location in __xenapi_locations:
160 v = __xenapi_records[__xenapi_locations[vdi.location]]
161 sm_config = v['sm_config']
162 if 'created' in sm_config:
163 vdi.sm_config['created'] = sm_config['created']
164 vdi.read_only = False
166# Now for the main functions:
167 def handles(type):
168 """Do we handle this type?"""
169 if type == TYPE:
170 return True
171 return False
172 handles = staticmethod(handles)
174 def content_type(self, sr_uuid):
175 """Returns the content_type XML"""
176 return super(ISOSR, self).content_type(sr_uuid)
178 # pylint: disable=no-member
179 vdi_path_regex = re.compile("[a-z0-9.-]+\.(iso|img)", re.I)
181 def vdi(self, uuid):
182 """Create a VDI class. If the VDI does not exist, we determine
183 here what its filename should be."""
185 filename = util.to_plain_string(self.srcmd.params.get('vdi_location'))
186 if filename is None:
187 smconfig = self.srcmd.params.get('vdi_sm_config')
188 if smconfig is None:
189 # uh, oh, a VDI.from_uuid()
190 import XenAPI
191 _VDI = self.session.xenapi.VDI
192 try:
193 vdi_ref = _VDI.get_by_uuid(uuid)
194 except XenAPI.Failure as e:
195 if e.details[0] != 'UUID_INVALID':
196 raise
197 else:
198 filename = _VDI.get_location(vdi_ref)
200 if filename is None:
201 # Get the filename from sm-config['path'], or use the UUID
202 # if the path param doesn't exist.
203 if smconfig and 'path' in smconfig:
204 filename = smconfig['path']
205 if not self.vdi_path_regex.match(filename):
206 raise xs_errors.XenError('VDICreate', \
207 opterr='Invalid path "%s"' % filename)
208 else:
209 filename = '%s.img' % uuid
211 return ISOVDI(self, filename)
213 def load(self, sr_uuid):
214 """Initialises the SR"""
215 # First of all, check we've got the correct keys in dconf
216 if 'location' not in self.dconf: 216 ↛ 217line 216 didn't jump to line 217, because the condition on line 216 was never true
217 raise xs_errors.XenError('ConfigLocationMissing')
219 # Construct the path we're going to mount under:
220 if "legacy_mode" in self.dconf:
221 self.mountpoint = util.to_plain_string(self.dconf['location'])
222 else:
223 # Verify the target address
224 self._checkTargetStr(self.dconf['location'])
225 self.mountpoint = os.path.join(SR.MOUNT_BASE, sr_uuid)
227 # Add on the iso_path value if there is one
228 if "iso_path" in self.dconf: 228 ↛ 229line 228 didn't jump to line 229, because the condition on line 228 was never true
229 iso_path = util.to_plain_string(self.dconf['iso_path'])
230 if iso_path.startswith("/"):
231 iso_path = iso_path[1:]
232 self.path = os.path.join(self.mountpoint, iso_path)
233 else:
234 self.path = self.mountpoint
236 # Handle optional dconf attributes
237 self.nfsversion = nfs.validate_nfsversion(self.dconf.get('nfsversion'))
239 # Fill the required SMB version
240 self.smbversion = SMB_VERSION_3
242 # Check if smb version is specified from client
243 self.is_smbversion_specified = False
245 # Some info we need:
246 self.sr_vditype = 'phy'
248 def delete(self, sr_uuid):
249 pass
251 def attach(self, sr_uuid):
252 """Std. attach"""
253 # Very-Legacy mode means the ISOs are in the local fs - so no need to attach.
254 if 'legacy_mode' in self.dconf:
255 # Verify path exists
256 if not os.path.exists(self.mountpoint):
257 raise xs_errors.XenError('ISOLocalPath')
258 return
260 # Check whether we're already mounted
261 if self._checkmount():
262 return
264 # Create the mountpoint if it's not already there
265 if not util.isdir(self.mountpoint): 265 ↛ 268line 265 didn't jump to line 268, because the condition on line 265 was never false
266 util.makedirs(self.mountpoint)
268 mountcmd = []
269 location = util.to_plain_string(self.dconf['location'])
270 # TODO: Have XC standardise iso type string
271 protocol = 'nfs_iso'
272 options = ''
274 if 'type' in self.dconf:
275 protocol = self.dconf['type']
276 elif ":/" not in location: 276 ↛ 279line 276 didn't jump to line 279, because the condition on line 276 was never false
277 protocol = 'cifs'
279 if 'options' in self.dconf:
280 options = self.dconf['options'].split(' ')
281 if protocol == 'cifs': 281 ↛ 284line 281 didn't jump to line 284, because the condition on line 281 was never false
282 options = [x for x in options if x != ""]
283 else:
284 options = self.getNFSOptions(options)
286 # SMB options are passed differently for create via
287 # XC/xe sr-create and create via xe-mount-iso-sr
288 # In both cases check if SMB version is passed are not.
289 # If not use self.smbversion.
290 if protocol == 'cifs':
291 if 'type' in self.dconf:
292 # Create via XC or sr-create
293 # Check for username and password
294 mountcmd = ["mount.cifs", location, self.mountpoint]
295 if 'vers' in self.dconf:
296 self.is_smbversion_specified = True
297 self.smbversion = self.dconf['vers']
298 util.SMlog("self.dconf['vers'] = %s" % self.dconf['vers'])
299 self.appendCIFSMountOptions(mountcmd)
300 else:
301 # Creation via xe-mount-iso-sr
302 try:
303 mountcmd = ["mount", location, self.mountpoint]
304 if options and options[0] == '-o': 304 ↛ 313line 304 didn't jump to line 313, because the condition on line 304 was never false
305 pos = options[1].find('vers=')
306 if pos == -1: 306 ↛ 307line 306 didn't jump to line 307, because the condition on line 306 was never true
307 options[1] += ',' + self.getSMBVersion()
308 else:
309 self.smbversion = self.getSMBVersionFromOptions(
310 options[1])
311 self.is_smbversion_specified = True
312 else:
313 raise ValueError
314 mountcmd.extend(options)
315 except ValueError:
316 raise xs_errors.XenError('ISOInvalidXeMountOptions')
317 # Check the validity of 'smbversion'.
318 # Raise an exception for any invalid version.
319 if self.smbversion not in [SMB_VERSION_1, SMB_VERSION_3]:
320 raise xs_errors.XenError('ISOInvalidSMBversion')
322 # Attempt mounting
323 try:
324 if protocol == 'nfs_iso':
325 # For NFS, do a soft mount with tcp as protocol. Since ISO SR is
326 # going to be r-only, a failure in nfs link can be reported back
327 # to the process waiting.
328 serv_path = location.split(':')
329 util._testHost(serv_path[0], NFSPORT, 'NFSTarget')
330 nfs.soft_mount(self.mountpoint, serv_path[0], serv_path[1],
331 'tcp', useroptions=options,
332 nfsversion=self.nfsversion)
333 else:
334 smb3_fail_reason = None
335 if self.smbversion in SMB_VERSION_3:
336 util.SMlog('ISOSR mount over smb 3.0')
337 try:
338 self.mountOverSMB(mountcmd)
339 except util.CommandException as inst:
340 if not self.is_smbversion_specified: 340 ↛ 358line 340 didn't jump to line 358, because the condition on line 340 was never false
341 util.SMlog('Retrying ISOSR mount over smb 1.0')
342 smb3_fail_reason = inst.reason
343 # mountcmd is constructed such that the last two
344 # items will contain -o argument and its value.
345 del mountcmd[-2:]
346 self.smbversion = SMB_VERSION_1
347 if not options: 347 ↛ 350line 347 didn't jump to line 350, because the condition on line 347 was never false
348 self.appendCIFSMountOptions(mountcmd)
349 else:
350 if options[0] == '-o':
351 # regex can be used here since we have
352 # already validated version entry
353 options[1] = re.sub('vers=3.0', 'vers=1.0',
354 options[1])
355 mountcmd.extend(options)
356 self.mountOverSMB(mountcmd)
357 else:
358 raise xs_errors.XenError(
359 'ISOMountFailure', opterr=inst.reason)
360 else:
361 util.SMlog('ISOSR mount over smb 1.0')
362 self.mountOverSMB(mountcmd)
363 except util.CommandException as inst:
364 if not self.is_smbversion_specified: 364 ↛ 368line 364 didn't jump to line 368, because the condition on line 364 was never false
365 raise xs_errors.XenError(
366 'ISOMountFailure', opterr=smb3_fail_reason)
367 else:
368 raise xs_errors.XenError(
369 'ISOMountFailure', opterr=inst.reason)
370 except nfs.NfsException as e:
371 raise xs_errors.XenError('ISOMountFailure', opterr=str(e.errstr))
373 # Check the iso_path is accessible
374 if not self._checkmount(): 374 ↛ 375line 374 didn't jump to line 375, because the condition on line 374 was never true
375 self.detach(sr_uuid)
376 raise xs_errors.XenError('ISOSharenameFailure')
378 def after_master_attach(self, uuid):
379 """Perform actions required after attaching on the pool master
380 Return:
381 None
382 """
383 # Nothing required here for ISOs and tools ISOs will fail if scanned
384 pass
386 def getSMBVersionFromOptions(self, options):
387 """Extract SMB version from options """
388 smb_ver = None
389 options_list = options.split(',')
390 for option in options_list: 390 ↛ 396line 390 didn't jump to line 396, because the loop on line 390 didn't complete
391 if option.startswith('vers='): 391 ↛ 390line 391 didn't jump to line 390, because the condition on line 391 was never false
392 version = option.split('=')
393 if len(version) == 2: 393 ↛ 395line 393 didn't jump to line 395, because the condition on line 393 was never false
394 smb_ver = version[1]
395 break
396 return smb_ver
398 def getSMBVersion(self):
399 """Pass smb version option to mount.cifs"""
400 smbversion = "vers=%s" % self.smbversion
401 return smbversion
403 def mountOverSMB(self, mountcmd):
404 """This function raises util.CommandException"""
405 new_env, domain = cifutils.getCIFCredentials(self.dconf, self.session,
406 prefix="cifs")
408 util.pread(mountcmd, True, new_env=new_env)
409 try:
410 if not self.is_smbversion_specified:
411 # Store the successful smb version in PBD config
412 self.updateSMBVersInPBDConfig()
413 except Exception as exc:
414 util.SMlog("Exception: %s" % str(exc))
415 if self._checkmount():
416 util.pread(["umount", self.mountpoint])
417 raise util.CommandException
419 def updateSMBVersInPBDConfig(self):
420 """Store smb version in PBD config"""
421 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
422 if pbd is not None:
423 util.SMlog('Updating SMB version in PBD device config')
424 dconf = self.session.xenapi.PBD.get_device_config(pbd)
425 dconf['vers'] = self.smbversion
426 self.session.xenapi.PBD.set_device_config(pbd, dconf)
427 else:
428 raise Exception('Could not find PBD for corresponding SR')
430 def getNFSOptions(self, options):
431 """Append options to mount.nfs"""
432 #Only return any options specified with -o
433 nfsOptions = ''
434 for index, opt in enumerate(options):
435 if opt == "-o":
436 nfsOptions = options[index + 1]
437 break
439 return nfsOptions
441 def appendCIFSMountOptions(self, mountcmd):
442 """Append options to mount.cifs"""
443 options = []
444 try:
445 options.append(self.getCacheOptions())
447 if not cifutils.containsCredentials(self.dconf, prefix="cifs"):
448 options.append('guest')
450 options.append(self.getSMBVersion())
452 username, domain = (
453 cifutils.splitDomainAndUsername(self.dconf['username'])
454 )
456 if domain:
457 options.append('domain=' + domain)
458 except:
459 util.SMlog("Exception while attempting to append mount options")
460 raise
462 # Extend mountcmd appropriately
463 if options: 463 ↛ exitline 463 didn't return from function 'appendCIFSMountOptions', because the condition on line 463 was never false
464 options = ",".join(str(x) for x in options if x)
465 mountcmd.extend(["-o", options])
467 def getCacheOptions(self):
468 """Pass cache options to mount.cifs"""
469 return "cache=none"
471 def detach(self, sr_uuid):
472 """Std. detach"""
473 if 'legacy_mode' in self.dconf or not self._checkmount(): 473 ↛ 476line 473 didn't jump to line 476, because the condition on line 473 was never false
474 return
476 try:
477 util.pread(["umount", self.mountpoint])
478 except util.CommandException as inst:
479 raise xs_errors.XenError('NFSUnMount', \
480 opterr='error is %d' % inst.code)
482 def scan(self, sr_uuid):
483 """Scan: see _loadvdis"""
484 if not util.isdir(self.path):
485 raise xs_errors.XenError('SRUnavailable', \
486 opterr='no such directory %s' % self.path)
488 if ('legacy_mode' not in self.dconf) and (not self._checkmount()):
489 raise xs_errors.XenError('SRUnavailable', \
490 opterr='directory not mounted: %s' % self.path)
492 #try:
493 if not self.vdis:
494 self._loadvdis()
495 self.physical_size = util.get_fs_size(self.path)
496 self.physical_utilisation = util.get_fs_utilisation(self.path)
497 self.virtual_allocation = self.physical_size
499 other_config = self.session.xenapi.SR.get_other_config(self.sr_ref)
501 if 'xenserver_tools_sr' in other_config and \
502 other_config['xenserver_tools_sr'] == "true":
503 # Out of all the xs-tools ISOs which exist in this dom0, we mark
504 # only one as the official one.
506 # Pass 1: find the latest version
507 latest_build_vdi = None
508 latest_build_number = "0"
509 for vdi_name in self.vdis:
510 vdi = self.vdis[vdi_name]
512 if latest_build_vdi is None:
513 latest_build_vdi = vdi.location
514 latest_build_number = "0"
516 if 'xs-tools-build' in vdi.sm_config:
517 bld = vdi.sm_config['xs-tools-build']
518 if bld >= latest_build_number:
519 latest_build_vdi = vdi.location
520 latest_build_number = bld
522 # Pass 2: mark all VDIs accordingly
523 for vdi_name in self.vdis:
524 vdi = self.vdis[vdi_name]
525 if vdi.location == latest_build_vdi:
526 vdi.sm_config['xs-tools'] = "true"
527 else:
528 if "xs-tools" in vdi.sm_config:
529 del vdi.sm_config['xs-tools']
531 # Synchronise the VDIs: this will update the sm_config maps of current records
532 scanrecord = SR.ScanRecord(self)
533 scanrecord.synchronise_new()
534 scanrecord.synchronise_existing()
536 # Everything that looks like an xs-tools ISO but which isn't the
537 # primary one will also be renamed "Old version of ..."
538 sr = self.session.xenapi.SR.get_by_uuid(sr_uuid)
539 all_vdis = self.session.xenapi.VDI.get_all_records_where("field \"SR\" = \"%s\"" % sr)
540 for vdi_ref in all_vdis.keys():
541 vdi = all_vdis[vdi_ref]
542 if 'xs-tools-version' in vdi['sm_config']:
543 name = tools_iso_name(vdi['location'])
544 if 'xs-tools' in vdi['sm_config']:
545 self.session.xenapi.VDI.set_name_label(vdi_ref, name)
546 else:
547 self.session.xenapi.VDI.set_name_label(vdi_ref, "Old version of " + name)
550 # never forget old VDI records to cope with rolling upgrade
551 for location in scanrecord.gone:
552 vdi = scanrecord.get_xenapi_vdi(location)
553 util.SMlog("Marking previous version of tools ISO: location=%s uuid=%s" % (vdi['location'], vdi['uuid']))
554 vdi = self.session.xenapi.VDI.get_by_uuid(vdi['uuid'])
555 name_label = self.session.xenapi.VDI.get_name_label(vdi)
556 if not(name_label.startswith("Old version of ")):
557 self.session.xenapi.VDI.set_name_label(vdi, "Old version of " + name_label)
558 # Mark it as missing for informational purposes only
559 self.session.xenapi.VDI.set_missing(vdi, True)
560 self.session.xenapi.VDI.remove_from_sm_config(vdi, 'xs-tools')
562 else:
563 return super(ISOSR, self).scan(sr_uuid)
565 def create(self, sr_uuid, size):
566 self.attach(sr_uuid)
567 if 'type' in self.dconf:
568 smconfig = self.session.xenapi.SR.get_sm_config(self.sr_ref)
569 smconfig['iso_type'] = self.dconf['type']
570 self.session.xenapi.SR.set_sm_config(self.sr_ref, smconfig)
572 # CA-80254: Check for iso/img files whose name consists of extended
573 # characters.
574 for f in util.listdir(self.path, quiet=True):
575 if is_image_utf8_compatible(f):
576 try:
577 f.encode('ascii')
578 except UnicodeEncodeError:
579 raise xs_errors.XenError('CIFSExtendedCharsNotSupported',
580 opterr='The repository contains at least one file whose name consists of extended characters.')
582 self.detach(sr_uuid)
585class ISOVDI(VDI.VDI):
586 def load(self, vdi_uuid):
587 # Nb, in the vdi_create call, the filename is unset, so the following
588 # will fail.
589 self.vdi_type = "iso"
590 try:
591 stat = os.stat(self.path)
592 self.utilisation = int(stat.st_size)
593 self.size = int(stat.st_size)
594 self.label = self.filename
595 except:
596 pass
598 def __init__(self, mysr, filename):
599 self.path = os.path.join(mysr.path, filename)
600 VDI.VDI.__init__(self, mysr, None)
601 self.location = filename
602 self.filename = filename
603 self.read_only = True
604 self.label = filename
605 self.sm_config = {}
606 if "legacy_mode" in mysr.dconf:
607 if filename.startswith("xs-tools") or filename.startswith("guest-tools"):
608 self.label = tools_iso_name(filename)
609 # Mark this as a Tools CD
610 # self.sm_config['xs-tools'] = 'true'
611 # Extract a version string, if present
612 vsn = filename[filename.find("tools") + len("tools"):][:-len(".iso")].strip("-").split("-", 1)
613 # "4.1.0"
614 if len(vsn) == 1:
615 build_number = "0" # string
616 product_version = vsn[0]
617 # "4.1.0-1234"
618 elif len(vsn) > 1:
619 build_number = vsn[1]
620 product_version = vsn[0]
621 else:
622 build_number = 0
623 product_version = "unknown"
624 util.SMlog("version=%s build=%s" % (product_version, build_number))
625 self.sm_config['xs-tools-version'] = product_version
626 self.sm_config['xs-tools-build'] = build_number
628 def detach(self, sr_uuid, vdi_uuid):
629 pass
631 def attach(self, sr_uuid, vdi_uuid):
632 try:
633 os.stat(self.path)
634 return super(ISOVDI, self).attach(sr_uuid, vdi_uuid)
635 except:
636 raise xs_errors.XenError('VDIMissing')
638 def create(self, sr_uuid, vdi_uuid, size):
639 self.uuid = vdi_uuid
640 self.path = os.path.join(self.sr.path, self.filename)
641 self.size = size
642 self.utilisation = 0
643 self.read_only = False
644 self.sm_config = self.sr.srcmd.params['vdi_sm_config']
645 self.sm_config['created'] = util._getDateString()
647 if util.pathexists(self.path):
648 raise xs_errors.XenError('VDIExists')
650 try:
651 handle = open(self.path, "w")
652 handle.truncate(size)
653 handle.close()
654 self._db_introduce()
655 return super(ISOVDI, self).get_params()
656 except Exception as exn:
657 util.SMlog("Exception when creating VDI: %s" % exn)
658 raise xs_errors.XenError('VDICreate', \
659 opterr='could not create file: "%s"' % self.path)
661 def delete(self, sr_uuid, vdi_uuid):
662 util.SMlog("Deleting...")
664 self.uuid = vdi_uuid
665 self._db_forget()
667 if not util.pathexists(self.path):
668 return
670 try:
671 util.SMlog("Unlinking...")
672 os.unlink(self.path)
673 util.SMlog("Done...")
674 except:
675 raise xs_errors.XenError('VDIDelete')
677 # delete, update, introduce unimplemented. super class will raise
678 # exceptions
680if __name__ == '__main__': 680 ↛ 681line 680 didn't jump to line 681, because the condition on line 680 was never true
681 SRCommand.run(ISOSR, DRIVER_INFO)
682else:
683 SR.registerSR(ISOSR)