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(r"\.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 r"([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(r"[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 # pylint: disable=import-error
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 smb3_fail_reason = None
324 try:
325 if protocol == 'nfs_iso':
326 # For NFS, do a soft mount with tcp as protocol. Since ISO SR is
327 # going to be r-only, a failure in nfs link can be reported back
328 # to the process waiting.
329 serv_path = location.split(':')
330 util._testHost(serv_path[0], NFSPORT, 'NFSTarget')
331 # Extract timeout and retrans values, if any
332 io_timeout = nfs.get_nfs_timeout(self.other_config)
333 io_retrans = nfs.get_nfs_retrans(self.other_config)
334 nfs.soft_mount(self.mountpoint, serv_path[0], serv_path[1],
335 'tcp', useroptions=options, nfsversion=self.nfsversion,
336 timeout=io_timeout, retrans=io_retrans)
337 else:
338 if self.smbversion in SMB_VERSION_3:
339 util.SMlog('ISOSR mount over smb 3.0')
340 try:
341 self.mountOverSMB(mountcmd)
342 except util.CommandException as inst:
343 if not self.is_smbversion_specified: 343 ↛ 361line 343 didn't jump to line 361, because the condition on line 343 was never false
344 util.SMlog('Retrying ISOSR mount over smb 1.0')
345 smb3_fail_reason = inst.reason
346 # mountcmd is constructed such that the last two
347 # items will contain -o argument and its value.
348 del mountcmd[-2:]
349 self.smbversion = SMB_VERSION_1
350 if not options: 350 ↛ 353line 350 didn't jump to line 353, because the condition on line 350 was never false
351 self.appendCIFSMountOptions(mountcmd)
352 else:
353 if options[0] == '-o':
354 # regex can be used here since we have
355 # already validated version entry
356 options[1] = re.sub('vers=3.0', 'vers=1.0',
357 options[1])
358 mountcmd.extend(options)
359 self.mountOverSMB(mountcmd)
360 else:
361 raise xs_errors.XenError(
362 'ISOMountFailure', opterr=inst.reason)
363 else:
364 util.SMlog('ISOSR mount over smb 1.0')
365 self.mountOverSMB(mountcmd)
366 except util.CommandException as inst:
367 if not self.is_smbversion_specified: 367 ↛ 371line 367 didn't jump to line 371, because the condition on line 367 was never false
368 raise xs_errors.XenError(
369 'ISOMountFailure', opterr=smb3_fail_reason)
370 else:
371 raise xs_errors.XenError(
372 'ISOMountFailure', opterr=inst.reason)
373 except nfs.NfsException as e:
374 raise xs_errors.XenError('ISOMountFailure', opterr=str(e.errstr))
376 # Check the iso_path is accessible
377 if not self._checkmount(): 377 ↛ 378line 377 didn't jump to line 378, because the condition on line 377 was never true
378 self.detach(sr_uuid)
379 raise xs_errors.XenError('ISOSharenameFailure')
381 def after_master_attach(self, uuid):
382 """Perform actions required after attaching on the pool master
383 Return:
384 None
385 """
386 # Nothing required here for ISOs and tools ISOs will fail if scanned
387 pass
389 def getSMBVersionFromOptions(self, options):
390 """Extract SMB version from options """
391 smb_ver = None
392 options_list = options.split(',')
393 for option in options_list: 393 ↛ 399line 393 didn't jump to line 399, because the loop on line 393 didn't complete
394 if option.startswith('vers='): 394 ↛ 393line 394 didn't jump to line 393, because the condition on line 394 was never false
395 version = option.split('=')
396 if len(version) == 2: 396 ↛ 398line 396 didn't jump to line 398, because the condition on line 396 was never false
397 smb_ver = version[1]
398 break
399 return smb_ver
401 def getSMBVersion(self):
402 """Pass smb version option to mount.cifs"""
403 smbversion = "vers=%s" % self.smbversion
404 return smbversion
406 def mountOverSMB(self, mountcmd):
407 """This function raises util.CommandException"""
408 new_env, domain = cifutils.getCIFCredentials(self.dconf, self.session,
409 prefix="cifs")
411 util.pread(mountcmd, True, new_env=new_env)
412 try:
413 if not self.is_smbversion_specified:
414 # Store the successful smb version in PBD config
415 self.updateSMBVersInPBDConfig()
416 except Exception as exc:
417 util.SMlog("Exception: %s" % str(exc))
418 if self._checkmount():
419 util.pread(["umount", self.mountpoint])
420 raise util.CommandException
422 def updateSMBVersInPBDConfig(self):
423 """Store smb version in PBD config"""
424 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
425 if pbd is not None:
426 util.SMlog('Updating SMB version in PBD device config')
427 dconf = self.session.xenapi.PBD.get_device_config(pbd)
428 dconf['vers'] = self.smbversion
429 self.session.xenapi.PBD.set_device_config(pbd, dconf)
430 else:
431 raise Exception('Could not find PBD for corresponding SR')
433 def getNFSOptions(self, options):
434 """Append options to mount.nfs"""
435 #Only return any options specified with -o
436 nfsOptions = ''
437 for index, opt in enumerate(options):
438 if opt == "-o":
439 nfsOptions = options[index + 1]
440 break
442 return nfsOptions
444 def appendCIFSMountOptions(self, mountcmd):
445 """Append options to mount.cifs"""
446 options = []
447 try:
448 options.append(self.getCacheOptions())
450 if not cifutils.containsCredentials(self.dconf, prefix="cifs"):
451 options.append('guest')
453 options.append(self.getSMBVersion())
455 username, domain = (
456 cifutils.splitDomainAndUsername(self.dconf['username'])
457 )
459 if domain:
460 options.append('domain=' + domain)
461 except:
462 util.SMlog("Exception while attempting to append mount options")
463 raise
465 # Extend mountcmd appropriately
466 if options: 466 ↛ exitline 466 didn't return from function 'appendCIFSMountOptions', because the condition on line 466 was never false
467 options = ",".join(str(x) for x in options if x)
468 mountcmd.extend(["-o", options])
470 def getCacheOptions(self):
471 """Pass cache options to mount.cifs"""
472 return "cache=none"
474 def detach(self, sr_uuid):
475 """Std. detach"""
476 if 'legacy_mode' in self.dconf or not self._checkmount(): 476 ↛ 479line 476 didn't jump to line 479, because the condition on line 476 was never false
477 return
479 try:
480 util.pread(["umount", self.mountpoint])
481 except util.CommandException as inst:
482 raise xs_errors.XenError('NFSUnMount', \
483 opterr='error is %d' % inst.code)
485 def scan(self, sr_uuid):
486 """Scan: see _loadvdis"""
487 if not util.isdir(self.path):
488 raise xs_errors.XenError('SRUnavailable', \
489 opterr='no such directory %s' % self.path)
491 if ('legacy_mode' not in self.dconf) and (not self._checkmount()):
492 raise xs_errors.XenError('SRUnavailable', \
493 opterr='directory not mounted: %s' % self.path)
495 #try:
496 if not self.vdis:
497 self._loadvdis()
498 self.physical_size = util.get_fs_size(self.path)
499 self.physical_utilisation = util.get_fs_utilisation(self.path)
500 self.virtual_allocation = self.physical_size
502 self.other_config = self.session.xenapi.SR.get_other_config(self.sr_ref)
504 if 'xenserver_tools_sr' in self.other_config and \
505 self.other_config['xenserver_tools_sr'] == "true":
506 # Out of all the xs-tools ISOs which exist in this dom0, we mark
507 # only one as the official one.
509 # Pass 1: find the latest version
510 latest_build_vdi = None
511 latest_build_number = "0"
512 for vdi_name in self.vdis:
513 vdi = self.vdis[vdi_name]
515 if latest_build_vdi is None:
516 latest_build_vdi = vdi.location
517 latest_build_number = "0"
519 if 'xs-tools-build' in vdi.sm_config:
520 bld = vdi.sm_config['xs-tools-build']
521 if bld >= latest_build_number:
522 latest_build_vdi = vdi.location
523 latest_build_number = bld
525 # Pass 2: mark all VDIs accordingly
526 for vdi_name in self.vdis:
527 vdi = self.vdis[vdi_name]
528 if vdi.location == latest_build_vdi:
529 vdi.sm_config['xs-tools'] = "true"
530 else:
531 if "xs-tools" in vdi.sm_config:
532 del vdi.sm_config['xs-tools']
534 # Synchronise the VDIs: this will update the sm_config maps of current records
535 scanrecord = SR.ScanRecord(self)
536 scanrecord.synchronise_new()
537 scanrecord.synchronise_existing()
539 # Everything that looks like an xs-tools ISO but which isn't the
540 # primary one will also be renamed "Old version of ..."
541 sr = self.session.xenapi.SR.get_by_uuid(sr_uuid)
542 all_vdis = self.session.xenapi.VDI.get_all_records_where("field \"SR\" = \"%s\"" % sr)
543 for vdi_ref in all_vdis.keys():
544 vdi = all_vdis[vdi_ref]
545 if 'xs-tools-version' in vdi['sm_config']:
546 name = tools_iso_name(vdi['location'])
547 if 'xs-tools' in vdi['sm_config']:
548 self.session.xenapi.VDI.set_name_label(vdi_ref, name)
549 else:
550 self.session.xenapi.VDI.set_name_label(vdi_ref, "Old version of " + name)
553 # never forget old VDI records to cope with rolling upgrade
554 for location in scanrecord.gone:
555 vdi = scanrecord.get_xenapi_vdi(location)
556 util.SMlog("Marking previous version of tools ISO: location=%s uuid=%s" % (vdi['location'], vdi['uuid']))
557 vdi = self.session.xenapi.VDI.get_by_uuid(vdi['uuid'])
558 name_label = self.session.xenapi.VDI.get_name_label(vdi)
559 if not(name_label.startswith("Old version of ")):
560 self.session.xenapi.VDI.set_name_label(vdi, "Old version of " + name_label)
561 # Mark it as missing for informational purposes only
562 self.session.xenapi.VDI.set_missing(vdi, True)
563 self.session.xenapi.VDI.remove_from_sm_config(vdi, 'xs-tools')
565 else:
566 return super(ISOSR, self).scan(sr_uuid)
568 def create(self, sr_uuid, size):
569 self.attach(sr_uuid)
570 if 'type' in self.dconf:
571 smconfig = self.session.xenapi.SR.get_sm_config(self.sr_ref)
572 smconfig['iso_type'] = self.dconf['type']
573 self.session.xenapi.SR.set_sm_config(self.sr_ref, smconfig)
575 # CA-80254: Check for iso/img files whose name consists of extended
576 # characters.
577 for f in util.listdir(self.path, quiet=True):
578 if is_image_utf8_compatible(f):
579 try:
580 f.encode('ascii')
581 except UnicodeEncodeError:
582 raise xs_errors.XenError('CIFSExtendedCharsNotSupported',
583 opterr='The repository contains at least one file whose name consists of extended characters.')
585 self.detach(sr_uuid)
588class ISOVDI(VDI.VDI):
589 def load(self, vdi_uuid):
590 # Nb, in the vdi_create call, the filename is unset, so the following
591 # will fail.
592 self.vdi_type = "iso"
593 try:
594 stat = os.stat(self.path)
595 self.utilisation = int(stat.st_size)
596 self.size = int(stat.st_size)
597 self.label = self.filename
598 except:
599 pass
601 def __init__(self, mysr, filename):
602 self.path = os.path.join(mysr.path, filename)
603 VDI.VDI.__init__(self, mysr, None)
604 self.location = filename
605 self.filename = filename
606 self.read_only = True
607 self.label = filename
608 self.sm_config = {}
609 if "legacy_mode" in mysr.dconf:
610 if filename.startswith("xs-tools") or filename.startswith("guest-tools"):
611 self.label = tools_iso_name(filename)
612 # Mark this as a Tools CD
613 # self.sm_config['xs-tools'] = 'true'
614 # Extract a version string, if present
615 vsn = filename[filename.find("tools") + len("tools"):][:-len(".iso")].strip("-").split("-", 1)
616 # "4.1.0"
617 if len(vsn) == 1:
618 build_number = "0" # string
619 product_version = vsn[0]
620 # "4.1.0-1234"
621 elif len(vsn) > 1:
622 build_number = vsn[1]
623 product_version = vsn[0]
624 else:
625 build_number = 0
626 product_version = "unknown"
627 util.SMlog("version=%s build=%s" % (product_version, build_number))
628 self.sm_config['xs-tools-version'] = product_version
629 self.sm_config['xs-tools-build'] = build_number
631 def detach(self, sr_uuid, vdi_uuid):
632 pass
634 def attach(self, sr_uuid, vdi_uuid):
635 try:
636 os.stat(self.path)
637 return super(ISOVDI, self).attach(sr_uuid, vdi_uuid)
638 except:
639 raise xs_errors.XenError('VDIMissing')
641 def create(self, sr_uuid, vdi_uuid, size):
642 self.uuid = vdi_uuid
643 self.path = os.path.join(self.sr.path, self.filename)
644 self.size = size
645 self.utilisation = 0
646 self.read_only = False
647 self.sm_config = self.sr.srcmd.params['vdi_sm_config']
648 self.sm_config['created'] = util._getDateString()
650 if util.pathexists(self.path):
651 raise xs_errors.XenError('VDIExists')
653 try:
654 handle = open(self.path, "w")
655 handle.truncate(size)
656 handle.close()
657 self._db_introduce()
658 return super(ISOVDI, self).get_params()
659 except Exception as exn:
660 util.SMlog("Exception when creating VDI: %s" % exn)
661 raise xs_errors.XenError('VDICreate', \
662 opterr='could not create file: "%s"' % self.path)
664 def delete(self, sr_uuid, vdi_uuid):
665 util.SMlog("Deleting...")
667 self.uuid = vdi_uuid
668 self._db_forget()
670 if not util.pathexists(self.path):
671 return
673 try:
674 util.SMlog("Unlinking...")
675 os.unlink(self.path)
676 util.SMlog("Done...")
677 except:
678 raise xs_errors.XenError('VDIDelete')
680 # delete, update, introduce unimplemented. super class will raise
681 # exceptions
683if __name__ == '__main__': 683 ↛ 684line 683 didn't jump to line 684, because the condition on line 683 was never true
684 SRCommand.run(ISOSR, DRIVER_INFO)
685else:
686 SR.registerSR(ISOSR)