def getCIFCredentials(dconf, session, prefix=""): credentials = None domain = None if (containsCredentials(dconf, prefix)): username, domain = splitDomainAndUsername(dconf['username']) credentials = {} credentials["USER"] = util.to_plain_string(username) util.SMlog("CIFS user = {user}".format(user=credentials["USER"])) key_password, key_secret = getDconfPasswordKey(prefix) if key_secret in dconf: password = util.get_secret(session, dconf[key_secret]) if password is not None: util.SMlog("Obtained CIFS password via secret") else: password = dconf[key_password] if password is not None: util.SMlog("Obtained CIFS password") credentials["PASSWD"] = util.to_plain_string(password) if credentials["PASSWD"] is not None: util.SMlog("Obtained CIFS plain text password") domain = util.to_plain_string(domain) else: util.SMlog("NOTE: No CIFS credentials found in dconf") return credentials, domain
def _walkXML(parent): Dict = {} if not parent.hasChildNodes(): if parent.nodeValue == None: return '' for node in parent.childNodes: if node.nodeType == Node.ELEMENT_NODE: # Print the element name Dict[util.to_plain_string(node.nodeName)] = "" # Walk over any text nodes in the current node content = [] for child in node.childNodes: if child.nodeType == Node.TEXT_NODE and \ child.nodeValue.strip(): content.append(child.nodeValue.strip()) if content: strContent = string.join(content) Dict[util.to_plain_string(node.nodeName)] = util.to_plain_string(strContent) else: # Walk the child nodes Dict[util.to_plain_string(node.nodeName)] = _walkXML(node) return Dict
def load(self, sr_uuid): """Initialises the SR""" # First of all, check we've got the correct keys in dconf if 'location' not in self.dconf: raise xs_errors.XenError('ConfigLocationMissing') # Construct the path we're going to mount under: if "legacy_mode" in self.dconf: self.mountpoint = util.to_plain_string(self.dconf['location']) else: # Verify the target address self._checkTargetStr(self.dconf['location']) self.mountpoint = os.path.join(SR.MOUNT_BASE, sr_uuid) # Add on the iso_path value if there is one if "iso_path" in self.dconf: 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: self.path = self.mountpoint # Handle optional dconf attributes self.nfsversion = nfs.validate_nfsversion(self.dconf.get('nfsversion')) # Fill the required SMB version self.smbversion = SMB_VERSION_3 # Check if smb version is specified from client self.is_smbversion_specified = False # Some info we need: self.sr_vditype = 'phy'
def _walkXML(parent): Dict = {} if not parent.hasChildNodes(): if parent.nodeValue is None: return '' for node in parent.childNodes: if node.nodeType == Node.ELEMENT_NODE: # Print the element name Dict[util.to_plain_string(node.nodeName)] = "" # Walk over any text nodes in the current node content = [] for child in node.childNodes: if child.nodeType == Node.TEXT_NODE and \ child.nodeValue.strip(): content.append(child.nodeValue.strip()) if content: strContent = string.join(content) Dict[util.to_plain_string( node.nodeName)] = util.to_plain_string(strContent) else: # Walk the child nodes Dict[util.to_plain_string(node.nodeName)] = _walkXML(node) return Dict
def getMountOptions(self): """Creates option string based on parameters provided""" options = ['sec=ntlm', 'cache=loose', 'vers=3.0', 'actimeo=0' ] if self.dconf.has_key('username') and \ (self.dconf.has_key('password') or self.dconf.has_key('password_secret')): dom_username = self.dconf['username'].split('\\') if len(dom_username) == 1: domain = None username = dom_username[0] elif len(dom_username) == 2: domain = dom_username[0] username = dom_username[1] else: raise SMBException("A maximum of 2 tokens are expected " "(<domain>\<username>). {} were given." .format(len(dom_username))) domain = util.to_plain_string(domain) username = util.to_plain_string(username) if self.dconf.has_key('password_secret'): password = util.get_secret( self.session, self.dconf['password_secret'] ) else: password = self.dconf['password'] password = util.to_plain_string(password) cred_str = 'username={}\npassword={}\n'.format(username, password) if domain: cred_str += 'domain={}\n'.format(domain) # Open credentials file and truncate try: with open(self.credentials, 'w') as f: f.write(cred_str) except IOError, e: raise SMBException("Failed to create credentials file") options.append('credentials=%s' % self.credentials)
def load(self, sr_uuid): """Initialises the SR""" if not 'location' in self.dconf: raise xs_errors.XenError('ConfigLocationMissing') self.path = util.to_plain_string(self.dconf['location']) self.sr_vditype = 'file'
def synchronise_gone(self): """Delete XenAPI record for old disks""" for location in self.gone: vdi = self.get_xenapi_vdi(location) util.SMlog("Forgetting VDI with location=%s uuid=%s" % (util.to_plain_string(vdi['location']), vdi['uuid'])) self.sr.forget_vdi(vdi['uuid'])
def vdi(self, 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 as 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 'path' in smconfig: 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)
def in_sync_with_xenapi_record(self, x): """Returns true if this VDI is in sync with the supplied XenAPI record""" if self.location <> util.to_plain_string(x['location']): util.SMlog("location %s <> %s" % (self.location, x['location'])) return False if self.read_only <> x['read_only']: util.SMlog("read_only %s <> %s" % (self.read_only, x['read_only'])) return False if str(self.size) <> x['virtual_size']: util.SMlog("virtual_size %s <> %s" % (self.size, x['virtual_size'])) return False if str(self.utilisation) <> x['physical_utilisation']: util.SMlog("utilisation %s <> %s" % (self.utilisation, x['physical_utilisation'])) return False sm_config = util.default(self, "sm_config", lambda: {}) if set(sm_config.keys()) <> set(x['sm_config'].keys()): util.SMlog("sm_config %s <> %s" % (repr(sm_config), repr(x['sm_config']))) return False for k in sm_config.keys(): if sm_config[k] <> x['sm_config'][k]: util.SMlog("sm_config %s <> %s" % (repr(sm_config), repr(x['sm_config']))) return False if self.cbt_enabled != x['cbt_enabled']: util.SMlog("cbt_enabled %s <> %s" % ( self.cbt_enabled, x['cbt_enabled'])) return False return True
def in_sync_with_xenapi_record(self, x): """Returns true if this VDI is in sync with the supplied XenAPI record""" if self.location <> util.to_plain_string(x['location']): util.SMlog("location %s <> %s" % (self.location, x['location'])) return False if self.read_only <> x['read_only']: util.SMlog("read_only %s <> %s" % (self.read_only, x['read_only'])) return False if str(self.size) <> x['virtual_size']: util.SMlog("virtual_size %s <> %s" % (self.size, x['virtual_size'])) return False if str(self.utilisation) <> x['physical_utilisation']: util.SMlog("utilisation %s <> %s" % (self.utilisation, x['physical_utilisation'])) return False sm_config = util.default(self, "sm_config", lambda: {}) if set(sm_config.keys()) <> set(x['sm_config'].keys()): util.SMlog("sm_config %s <> %s" % (repr(sm_config), repr(x['sm_config']))) return False for k in sm_config.keys(): if sm_config[k] <> x['sm_config'][k]: util.SMlog("sm_config %s <> %s" % (repr(sm_config), repr(x['sm_config']))) return False if self.cbt_enabled != x['cbt_enabled']: util.SMlog("cbt_enabled %s <> %s" % (self.cbt_enabled, x['cbt_enabled'])) return False return True
def __init__(self, sr): self.sr = sr self.__xenapi_locations = {} self.__xenapi_records = util.list_VDI_records_in_sr(sr) for vdi in self.__xenapi_records.keys(): self.__xenapi_locations[util.to_plain_string( self.__xenapi_records[vdi]['location'])] = vdi self.__sm_records = {} for vdi in sr.vdis.values(): # We initialise the sm_config field with the values from the database # The sm_config_overrides contains any new fields we want to add to # sm_config, and also any field to delete (by virtue of having # sm_config_overrides[key]=None) try: if not hasattr(vdi, "sm_config"): vdi.sm_config = self.__xenapi_records[ self.__xenapi_locations[ vdi.location]]['sm_config'].copy() except: util.SMlog("missing config for vdi: %s" % vdi.location) vdi.sm_config = {} vdi._override_sm_config(vdi.sm_config) self.__sm_records[vdi.location] = vdi xenapi_locations = set(self.__xenapi_locations.keys()) sm_locations = set(self.__sm_records.keys()) # These ones are new on disk self.new = sm_locations.difference(xenapi_locations) # These have disappeared from the disk self.gone = xenapi_locations.difference(sm_locations) # These are the ones which are still present but might have changed... existing = sm_locations.intersection(xenapi_locations) # Synchronise the uuid fields using the location as the primary key # This ensures we know what the UUIDs are even though they aren't stored # in the storage backend. for location in existing: sm_vdi = self.get_sm_vdi(location) xenapi_vdi = self.get_xenapi_vdi(location) sm_vdi.uuid = util.default(sm_vdi, "uuid", lambda: xenapi_vdi['uuid']) # Only consider those whose configuration looks different self.existing = filter( lambda x: not (self.get_sm_vdi(x).in_sync_with_xenapi_record( self.get_xenapi_vdi(x))), existing) if len(self.new) <> 0: util.SMlog("new VDIs on disk: " + repr(self.new)) if len(self.gone) <> 0: util.SMlog("VDIs missing from disk: " + repr(self.gone)) if len(self.existing) <> 0: util.SMlog("VDIs changed on disk: " + repr(self.existing))
def getCIFCredentials(dconf, session, prefix=""): credentials = None domain = None if (containsCredentials(dconf, prefix)): username, domain = splitDomainAndUsername(dconf['username']) credentials = {} credentials["USER"] = util.to_plain_string(username) key_password, key_secret = getDconfPasswordKey(prefix) if key_secret in dconf: password = util.get_secret(session, dconf[key_secret]) else: password = dconf[key_password] credentials["PASSWD"] = util.to_plain_string(password) domain = util.to_plain_string(domain) return credentials, domain
def synchronise_gone(self): """Delete XenAPI record for old disks""" for location in self.gone: vdi = self.get_xenapi_vdi(location) util.SMlog("Forgetting VDI with location=%s uuid=%s" % (util.to_plain_string(vdi['location']), vdi['uuid'])) try: self.sr.forget_vdi(vdi['uuid']) except XenAPI.Failure, e: if e.details == "HANDLE_INVALID" or e.details == "UUID_INVALID": util.SMlog("VDI %s not found, ignoring exception" % vdi['uuid']) else: raise
def synchronise_gone(self): """Delete XenAPI record for old disks""" for location in self.gone: vdi = self.get_xenapi_vdi(location) util.SMlog("Forgetting VDI with location=%s uuid=%s" % (util.to_plain_string(vdi['location']), vdi['uuid'])) try: self.sr.forget_vdi(vdi['uuid']) except XenAPI.Failure, e: if util.isInvalidVDI(e): util.SMlog("VDI %s not found, ignoring exception" \ % vdi['uuid']) else: raise
def synchronise_gone(self): """Delete XenAPI record for old disks""" for location in self.gone: vdi = self.get_xenapi_vdi(location) util.SMlog("Forgetting VDI with location=%s uuid=%s" % (util.to_plain_string(vdi['location']), vdi['uuid'])) try: self.sr.forget_vdi(vdi['uuid']) except XenAPI.Failure, e: if e.details == "HANDLE_INVALID" or e.details == "UUID_INVALID": util.SMlog("VDI %s not found, ignoring exception" % uuid) else: raise
def __init__(self, sr): self.sr = sr self.__xenapi_locations = {} self.__xenapi_records = util.list_VDI_records_in_sr(sr) for vdi in self.__xenapi_records.keys(): self.__xenapi_locations[util.to_plain_string(self.__xenapi_records[vdi]['location'])] = vdi self.__sm_records = {} for vdi in sr.vdis.values(): # We initialise the sm_config field with the values from the database # The sm_config_overrides contains any new fields we want to add to # sm_config, and also any field to delete (by virtue of having # sm_config_overrides[key]=None) try: if not hasattr(vdi, "sm_config"): vdi.sm_config = self.__xenapi_records[self.__xenapi_locations[vdi.location]]['sm_config'].copy() except: util.SMlog("missing config for vdi: %s" % vdi.location) vdi.sm_config = {} vdi._override_sm_config(vdi.sm_config) self.__sm_records[vdi.location] = vdi xenapi_locations = set(self.__xenapi_locations.keys()) sm_locations = set(self.__sm_records.keys()) # These ones are new on disk self.new = sm_locations.difference(xenapi_locations) # These have disappeared from the disk self.gone = xenapi_locations.difference(sm_locations) # These are the ones which are still present but might have changed... existing = sm_locations.intersection(xenapi_locations) # Synchronise the uuid fields using the location as the primary key # This ensures we know what the UUIDs are even though they aren't stored # in the storage backend. for location in existing: sm_vdi = self.get_sm_vdi(location) xenapi_vdi = self.get_xenapi_vdi(location) sm_vdi.uuid = util.default(sm_vdi, "uuid", lambda: xenapi_vdi['uuid']) # Only consider those whose configuration looks different self.existing = filter(lambda x:not(self.get_sm_vdi(x).in_sync_with_xenapi_record(self.get_xenapi_vdi(x))), existing) if len(self.new) <> 0: util.SMlog("new VDIs on disk: " + repr(self.new)) if len(self.gone) <> 0: util.SMlog("VDIs missing from disk: " + repr(self.gone)) if len(self.existing) <> 0: util.SMlog("VDIs changed on disk: " + repr(self.existing))
def vdi(self, 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() _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)
def attach(self, sr_uuid): """Std. attach""" # Very-Legacy mode means the ISOs are in the local fs - so no need to attach. if 'legacy_mode' in self.dconf: # Verify path exists if not os.path.exists(self.mountpoint): raise xs_errors.XenError('ISOLocalPath') return # Check whether we're already mounted if self._checkmount(): return # Create the mountpoint if it's not already there if not util.isdir(self.mountpoint): util.makedirs(self.mountpoint) mountcmd = [] location = util.to_plain_string(self.dconf['location']) # TODO: Have XC standardise iso type string protocol = 'nfs_iso' options = '' if 'type' in self.dconf: protocol = self.dconf['type'] elif ":/" not in location: protocol = 'cifs' if 'options' in self.dconf: options = self.dconf['options'].split(' ') if protocol == 'cifs': options = filter(lambda x: x != "", options) 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. if protocol == 'cifs': if 'type' in self.dconf: # Create via XC or sr-create # Check for username and password mountcmd = ["mount.cifs", location, self.mountpoint] if 'vers' in self.dconf: self.is_smbversion_specified = True self.smbversion = self.dconf['vers'] util.SMlog("self.dconf['vers'] = %s" % self.dconf['vers']) self.appendCIFSMountOptions(mountcmd) else: # Creation via xe-mount-iso-sr try: mountcmd = ["mount", location, self.mountpoint] if options and options[0] == '-o': pos = options[1].find('vers=') if pos == -1: options[1] += ',' + self.getSMBVersion() else: self.smbversion = self.getSMBVersionFromOptions( options[1]) self.is_smbversion_specified = True else: raise ValueError mountcmd.extend(options) except ValueError: raise xs_errors.XenError('ISOInvalidXeMountOptions') # Check the validity of 'smbversion'. # Raise an exception for any invalid version. if self.smbversion not in [SMB_VERSION_1, SMB_VERSION_3]: raise xs_errors.XenError('ISOInvalidSMBversion') # Attempt mounting try: if protocol == 'nfs_iso': # 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. serv_path = location.split(':') util._testHost(serv_path[0], NFSPORT, 'NFSTarget') nfs.soft_mount(self.mountpoint, serv_path[0], serv_path[1], 'tcp', useroptions=options, nfsversion=self.nfsversion) else: smb3_fail_reason = None if self.smbversion in SMB_VERSION_3: util.SMlog('ISOSR mount over smb 3.0') try: self.mountOverSMB(mountcmd) except util.CommandException as inst: if not self.is_smbversion_specified: util.SMlog('Retrying ISOSR mount over smb 1.0') smb3_fail_reason = inst.reason # mountcmd is constructed such that the last two # items will contain -o argument and its value. del mountcmd[-2:] self.smbversion = SMB_VERSION_1 if not options: self.appendCIFSMountOptions(mountcmd) 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) self.mountOverSMB(mountcmd) else: raise xs_errors.XenError('ISOMountFailure', opterr=inst.reason) else: util.SMlog('ISOSR mount over smb 1.0') self.mountOverSMB(mountcmd) except util.CommandException as inst: if not self.is_smbversion_specified: raise xs_errors.XenError('ISOMountFailure', opterr=smb3_fail_reason) else: raise xs_errors.XenError('ISOMountFailure', opterr=inst.reason) # Check the iso_path is accessible if not self._checkmount(): self.detach(sr_uuid) raise xs_errors.XenError('ISOSharenameFailure')