Coverage for drivers/ISOSR : 36%

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
#!/usr/bin/python # # Copyright (C) Citrix Systems Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; version 2.1 only. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # ISOSR: remote iso storage repository
"SR_SCAN", "SR_ATTACH", "SR_DETACH"]
[ [ 'location', 'path to mount (required) (e.g. server:/path)' ], [ 'options', 'extra options to pass to mount (deprecated) (e.g. \'-o ro\')' ], [ 'type','cifs or nfs'], nfs.NFS_VERSION]
'name': 'ISO', 'description': 'Handles CD images stored as files in iso format', 'vendor': 'Citrix Systems Inc', 'copyright': '(C) 2008 Citrix Systems Inc', 'driver_version': '1.0', 'required_api_version': '1.0', 'capabilities': CAPABILITIES, 'configuration': CONFIGURATION }
regex = re.compile("\.iso$|\.img$", re.I) if regex.search(s) == None: return False
# Check for extended characters if type(s) == str: try: s.decode('utf-8') except UnicodeDecodeError, e: util.SMlog("WARNING: This string is not UTF-8 compatible.") return False return True
# The tools ISO used have a "xs-" prefix in its name. # We recognise both and set the name_label accordingly. if filename[:3] == "xs-": return "xs-tools.iso" else: return "guest-tools.iso"
"""Local file storage repository"""
# Some helper functions: """Checks that the mountpoint exists and is mounted""" try: ismount = util.ismount(self.mountpoint) except util.CommandException, inst: return False return ismount
tgt = '' if re.search('^//',location): tgt = location.split('/')[2] elif re.search(r'^\\',location): l = location.split('\\') for i in location.split('\\'): if i: tgt = i break if not tgt: raise xs_errors.XenError('ISOLocationStringError') else: raise xs_errors.XenError('ISOLocationStringError')
except: raise xs_errors.XenError('DNSError')
"([0-9a-f]{8}-(([0-9a-f]{4})-){3}[0-9a-f]{12})\.(iso|img)", re.I) """Scan the directory and get uuids either from the VDI filename, \ or by creating a new one.""" if self.vdis: return
for name in filter(is_image_utf8_compatible, util.listdir(self.path, quiet = True)): fileName = self.path + "/" + name if os.path.isdir(fileName): util.SMlog("_loadvdis : %s is a directory. Ignore" % fileName) continue
# CA-80254: Check for iso/img files whose name consists of extended # characters. try: name.decode('ascii') except UnicodeDecodeError: raise xs_errors.XenError('CIFSExtendedCharsNotSupported', \ opterr = 'The repository contains at least one file whose name consists of extended characters.')
self.vdis[name] = ISOVDI(self, name) # Set the VDI UUID if the filename is of the correct form. # Otherwise, one will be generated later in VDI._db_introduce. m = self.uuid_file_regex.match(name) if m: self.vdis[name].uuid = m.group(1)
# Synchronise the read-only status with existing VDI records __xenapi_records = util.list_VDI_records_in_sr(self) __xenapi_locations = {} for vdi in __xenapi_records.keys(): __xenapi_locations[__xenapi_records[vdi]['location']] = vdi for vdi in self.vdis.values(): if vdi.location in __xenapi_locations: v = __xenapi_records[__xenapi_locations[vdi.location]] sm_config = v['sm_config'] if sm_config.has_key('created'): vdi.sm_config['created'] = sm_config['created'] vdi.read_only = False
# Now for the main functions: """Do we handle this type?""" if type == TYPE: return True return False
"""Returns the content_type XML""" return super(ISOSR, self).content_type(sr_uuid)
"""Create a VDI class. If the VDI does not exist, we determine here what its filename should be."""
filename = util.to_plain_string(self.srcmd.params.get('vdi_location')) if filename is None: smconfig = self.srcmd.params.get('vdi_sm_config') if smconfig is None: # uh, oh, a VDI.from_uuid() import XenAPI _VDI = self.session.xenapi.VDI try: vdi_ref = _VDI.get_by_uuid(uuid) except XenAPI.Failure, e: if e.details[0] != 'UUID_INVALID': raise else: filename = _VDI.get_location(vdi_ref)
if filename is None: # Get the filename from sm-config['path'], or use the UUID # if the path param doesn't exist. if smconfig and smconfig.has_key('path'): filename = smconfig['path'] if not self.vdi_path_regex.match(filename): raise xs_errors.XenError('VDICreate', \ opterr='Invalid path "%s"' % filename) else: filename = '%s.img' % uuid
return ISOVDI(self, filename)
"""Initialises the SR""" # First of all, check we've got the correct keys in dconf raise xs_errors.XenError('ConfigLocationMissing')
# Construct the path we're going to mount under: else: # Verify the target address
# Add on the iso_path value if there is one iso_path = util.to_plain_string(self.dconf['iso_path']) if iso_path.startswith("/"): iso_path=iso_path[1:] self.path = os.path.join(self.mountpoint, iso_path) else:
# Handle optional dconf attributes
# Fill the required SMB version
# Check if smb version is specified from client
# Some info we need:
pass
"""Std. attach""" # Very-Legacy mode means the ISOs are in the local fs - so no need to attach. # Verify path exists
# Check whether we're already mounted
# Create the mountpoint if it's not already there
# TODO: Have XC standardise iso type string
else: options = self.getNFSOptions(options)
# SMB options are passed differently for create via # XC/xe sr-create and create via xe-mount-iso-sr # In both cases check if SMB version is passed are not. # If not use self.smbversion. # Create via XC or sr-create # Check for username and password else: # Creation via xe-mount-iso-sr options[1] += ',' + self.getSMBVersion() else: options[1]) else: raise ValueError except ValueError: raise xs_errors.XenError('ISOInvalidXeMountOptions') # Check the validity of 'smbversion'. # Raise an exception for any invalid version.
# Attempt mounting # For NFS, do a soft mount with tcp as protocol. Since ISO SR is # going to be r-only, a failure in nfs link can be reported back # to the process waiting. 'tcp', useroptions=options, nfsversion=self.nfsversion) else: # mountcmd is constructed such that the last two # items will contain -o argument and its value. else: if options[0] == '-o': # regex can be used here since we have # already validated version entry options[1] = re.sub('vers=3.0', 'vers=1.0', options[1]) mountcmd.extend(options) else: raise xs_errors.XenError( 'ISOMountFailure', opterr=inst.reason) else: 'ISOMountFailure', opterr=smb3_fail_reason) else: raise xs_errors.XenError( 'ISOMountFailure', opterr=inst.reason)
# Check the iso_path is accessible self.detach(sr_uuid) raise xs_errors.XenError('ISOSharenameFailure')
"""Perform actions required after attaching on the pool master Return: None """ # Nothing required here for ISOs and tools ISOs will fail if scanned pass
"""Extract SMB version from options """
"""Pass smb version option to mount.cifs"""
"""This function raises util.CommandException""" prefix="cifs")
# Store the successful smb version in PBD config except Exception as exc: util.SMlog("Exception: %s" % str(exc)) if self._checkmount(): util.pread(["umount", self.mountpoint]) raise util.CommandException
"""Store smb version in PBD config""" pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref) if pbd is not None: util.SMlog('Updating SMB version in PBD device config') dconf = self.session.xenapi.PBD.get_device_config(pbd) dconf['vers'] = self.smbversion self.session.xenapi.PBD.set_device_config(pbd, dconf) else: raise Exception('Could not find PBD for corresponding SR')
"""Append options to mount.nfs""" #Only return any options specified with -o nfsOptions = '' for index, opt in enumerate(options): if opt == "-o": nfsOptions = options[index + 1] break
return nfsOptions
"""Append options to mount.cifs"""
cifutils.splitDomainAndUsername(self.dconf['username']) )
except: util.SMlog("Exception while attempting to append mount options") raise
# Extend mountcmd appropriately
"""Pass cache options to mount.cifs"""
"""Std. detach"""
try: util.pread(["umount", self.mountpoint]); except util.CommandException, inst: raise xs_errors.XenError('NFSUnMount', \ opterr = 'error is %d' % inst.code)
"""Scan: see _loadvdis""" if not util.isdir(self.path): raise xs_errors.XenError('SRUnavailable', \ opterr = 'no such directory %s' % self.path)
if (not self.dconf.has_key('legacy_mode')) and (not self._checkmount()): raise xs_errors.XenError('SRUnavailable', \ opterr = 'directory not mounted: %s' % self.path)
#try: if not self.vdis: self._loadvdis() self.physical_size = util.get_fs_size(self.path) self.physical_utilisation = util.get_fs_utilisation(self.path) self.virtual_allocation = self.physical_size
other_config = self.session.xenapi.SR.get_other_config(self.sr_ref)
if other_config.has_key('xenserver_tools_sr') and \ other_config['xenserver_tools_sr'] == "true": # Out of all the xs-tools ISOs which exist in this dom0, we mark # only one as the official one.
# Pass 1: find the latest version latest_build_vdi = None latest_build_number = "0" for vdi_name in self.vdis: vdi = self.vdis[vdi_name]
if latest_build_vdi == None: latest_build_vdi = vdi.location latest_build_number = "0"
if vdi.sm_config.has_key('xs-tools-build'): bld = vdi.sm_config['xs-tools-build'] if bld >= latest_build_number: latest_build_vdi = vdi.location latest_build_number = bld
# Pass 2: mark all VDIs accordingly for vdi_name in self.vdis: vdi = self.vdis[vdi_name] if vdi.location == latest_build_vdi: vdi.sm_config['xs-tools'] = "true" else: if vdi.sm_config.has_key("xs-tools"): del vdi.sm_config['xs-tools']
# Synchronise the VDIs: this will update the sm_config maps of current records scanrecord = SR.ScanRecord(self) scanrecord.synchronise_new() scanrecord.synchronise_existing()
# Everything that looks like an xs-tools ISO but which isn't the # primary one will also be renamed "Old version of ..." sr = self.session.xenapi.SR.get_by_uuid(sr_uuid) all_vdis = self.session.xenapi.VDI.get_all_records_where("field \"SR\" = \"%s\"" % sr) for vdi_ref in all_vdis.keys(): vdi = all_vdis[vdi_ref] if vdi['sm_config'].has_key('xs-tools-version'): name = tools_iso_name(vdi['location']) if vdi['sm_config'].has_key('xs-tools'): self.session.xenapi.VDI.set_name_label(vdi_ref, name) else: self.session.xenapi.VDI.set_name_label(vdi_ref, "Old version of " + name)
# never forget old VDI records to cope with rolling upgrade for location in scanrecord.gone: vdi = scanrecord.get_xenapi_vdi(location) util.SMlog("Marking previous version of tools ISO: location=%s uuid=%s" % (vdi['location'], vdi['uuid'])) vdi = self.session.xenapi.VDI.get_by_uuid(vdi['uuid']) name_label = self.session.xenapi.VDI.get_name_label(vdi) if not(name_label.startswith("Old version of ")): self.session.xenapi.VDI.set_name_label(vdi, "Old version of " + name_label) # Mark it as missing for informational purposes only self.session.xenapi.VDI.set_missing(vdi, True) self.session.xenapi.VDI.remove_from_sm_config(vdi, 'xs-tools' )
else: return super(ISOSR, self).scan(sr_uuid)
self.attach(sr_uuid) if self.dconf.has_key('type'): smconfig = self.session.xenapi.SR.get_sm_config(self.sr_ref) smconfig['iso_type'] = self.dconf['type'] self.session.xenapi.SR.set_sm_config(self.sr_ref, smconfig)
# CA-80254: Check for iso/img files whose name consists of extended # characters. for f in util.listdir(self.path, quiet = True): if is_image_utf8_compatible(f): try: f.decode('ascii') except UnicodeDecodeError: raise xs_errors.XenError('CIFSExtendedCharsNotSupported', opterr = 'The repository contains at least one file whose name consists of extended characters.')
self.detach(sr_uuid)
# Nb, in the vdi_create call, the filename is unset, so the following # will fail. self.vdi_type = "iso" try: stat = os.stat(self.path) self.utilisation = long(stat.st_size) self.size = long(stat.st_size) self.label = self.filename except: pass
self.path = os.path.join(mysr.path, filename) VDI.VDI.__init__(self, mysr, None) self.location = filename self.filename = filename self.read_only = True self.label = filename self.sm_config = {} if mysr.dconf.has_key("legacy_mode"): if filename.startswith("xs-tools") or filename.startswith("guest-tools"): self.label = tools_iso_name(filename) # Mark this as a Tools CD # self.sm_config['xs-tools'] = 'true' # Extract a version string, if present vsn = filename[filename.find("tools")+len("tools"):][:-len(".iso")].strip("-").split("-",1) # "4.1.0" if len(vsn) == 1: build_number="0" # string product_version=vsn[0] # "4.1.0-1234" elif len(vsn) > 1: build_number=vsn[1] product_version=vsn[0] else: build_number=0 product_version="unknown" util.SMlog("version=%s build=%s" % (product_version, build_number)) self.sm_config['xs-tools-version'] = product_version self.sm_config['xs-tools-build'] = build_number
pass
try: os.stat(self.path) return super(ISOVDI, self).attach(sr_uuid, vdi_uuid) except: raise xs_errors.XenError('VDIMissing')
self.uuid = vdi_uuid self.path = os.path.join(self.sr.path, self.filename) self.size = size self.utilisation = 0L self.read_only = False self.sm_config = self.sr.srcmd.params['vdi_sm_config'] self.sm_config['created'] = util._getDateString()
if util.pathexists(self.path): raise xs_errors.XenError('VDIExists')
try: handle = open(self.path,"w") handle.truncate(size) handle.close() self._db_introduce() return super(ISOVDI, self).get_params() except Exception, exn: util.SMlog("Exception when creating VDI: %s" % exn) raise xs_errors.XenError('VDICreate', \ opterr='could not create file: "%s"' % self.path)
util.SMlog("Deleting...")
self.uuid = vdi_uuid self._db_forget()
if not util.pathexists(self.path): return
try: util.SMlog("Unlinking...") os.unlink(self.path) util.SMlog("Done...") except: raise xs_errors.XenError('VDIDelete')
# delete, update, introduce unimplemented. super class will raise # exceptions
SRCommand.run(ISOSR, DRIVER_INFO) else: |