def clone(self, sr_uuid, vdi_uuid): dest = util.gen_uuid () args = [] args.append("vdi_clone") args.append(sr_uuid) args.append(vdi_uuid) args.append(dest) if self.hidden: raise xs_errors.XenError('VDIClone', opterr='hidden VDI') depth = vhdutil.getDepth(self.path) if depth == -1: raise xs_errors.XenError('VDIUnavailable', \ opterr='failed to get VHD depth') elif depth >= vhdutil.MAX_CHAIN_SIZE: raise xs_errors.XenError('SnapshotChainTooLong') # Test the amount of actual disk space if ENFORCE_VIRT_ALLOC: self.sr._loadvdis() reserved = self.sr.virtual_allocation sr_size = self.sr._getsize() if (sr_size - reserved) < \ ((self.size + VDI.VDIMetadataSize(SR.DEFAULT_TAP, self.size))*2): raise xs_errors.XenError('SRNoSpace') newuuid = util.gen_uuid() src = self.path dst = os.path.join(self.sr.path, "%s.%s" % (dest,self.vdi_type)) newsrc = os.path.join(self.sr.path, "%s.%s" % (newuuid,self.vdi_type)) newsrcname = "%s.%s" % (newuuid,self.vdi_type) if not self._checkpath(src): raise xs_errors.XenError('VDIUnavailable', \ opterr='VDI %s unavailable %s' % (vdi_uuid, src)) # wkcfix: multiphase util.start_log_entry(self.sr.path, self.path, args) # We assume the filehandle has been released try: try: util.ioretry(lambda: os.rename(src,newsrc)) except util.CommandException, inst: if inst.code != errno.ENOENT: # failed to rename, simply raise error util.end_log_entry(self.sr.path, self.path, ["error"]) raise try: util.ioretry(lambda: self._dualsnap(src, dst, newsrcname)) # mark the original file (in this case, its newsrc) # as hidden so that it does not show up in subsequent scans util.ioretry(lambda: self._mark_hidden(newsrc)) except util.CommandException, inst: if inst.code != errno.EIO: raise
def _snapshot(self, snap_type): util.SMlog("FileVDI._snapshot for %s (type %s)" % (self.uuid, snap_type)) args = [] args.append("vdi_clone") args.append(self.sr.uuid) args.append(self.uuid) dest = None dst = None if snap_type == self.SNAPSHOT_DOUBLE: dest = util.gen_uuid() dst = os.path.join(self.sr.path, "%s.%s" % (dest, self.vdi_type)) args.append(dest) if self.hidden: raise xs_errors.XenError('VDIClone', opterr='hidden VDI') depth = vhdutil.getDepth(self.path) if depth == -1: raise xs_errors.XenError('VDIUnavailable', \ opterr='failed to get VHD depth') elif depth >= vhdutil.MAX_CHAIN_SIZE: raise xs_errors.XenError('SnapshotChainTooLong') # Test the amount of actual disk space if ENFORCE_VIRT_ALLOC: self.sr._loadvdis() reserved = self.sr.virtual_allocation sr_size = self.sr._getsize() num_vdis = 2 if snap_type == self.SNAPSHOT_SINGLE: num_vdis = 1 if (sr_size - reserved) < ((self.size + VDI.VDIMetadataSize( \ vhdutil.VDI_TYPE_VHD, self.size)) * num_vdis): raise xs_errors.XenError('SRNoSpace') newuuid = util.gen_uuid() src = self.path newsrc = os.path.join(self.sr.path, "%s.%s" % (newuuid, self.vdi_type)) newsrcname = "%s.%s" % (newuuid, self.vdi_type) if not self._checkpath(src): raise xs_errors.XenError('VDIUnavailable', \ opterr='VDI %s unavailable %s' % (self.uuid, src)) # wkcfix: multiphase util.start_log_entry(self.sr.path, self.path, args) # We assume the filehandle has been released try: try: util.ioretry(lambda: os.rename(src, newsrc)) except util.CommandException, inst: if inst.code != errno.ENOENT: # failed to rename, simply raise error util.end_log_entry(self.sr.path, self.path, ["error"]) raise try: util.ioretry(lambda: self._snap(src, newsrcname)) if snap_type == self.SNAPSHOT_DOUBLE: util.ioretry(lambda: self._snap(dst, newsrcname)) # mark the original file (in this case, its newsrc) # as hidden so that it does not show up in subsequent scans util.ioretry(lambda: self._mark_hidden(newsrc)) except util.CommandException, inst: if inst.code != errno.EIO: raise
def _snapshot(self, snap_type, cbtlog=None, cbt_consistency=None): util.SMlog("FileVDI._snapshot for %s (type %s)" % (self.uuid, snap_type)) args = [] args.append("vdi_clone") args.append(self.sr.uuid) args.append(self.uuid) dest = None dst = None if snap_type == VDI.SNAPSHOT_DOUBLE: dest = util.gen_uuid() dst = os.path.join(self.sr.path, "%s.%s" % (dest, self.vdi_type)) args.append(dest) if self.hidden: raise xs_errors.XenError('VDIClone', opterr='hidden VDI') depth = vhdutil.getDepth(self.path) if depth == -1: raise xs_errors.XenError('VDIUnavailable', \ opterr='failed to get VHD depth') elif depth >= vhdutil.MAX_CHAIN_SIZE: raise xs_errors.XenError('SnapshotChainTooLong') # Test the amount of actual disk space if ENFORCE_VIRT_ALLOC: self.sr._loadvdis() reserved = self.sr.virtual_allocation sr_size = self.sr._getsize() num_vdis = 2 if (snap_type == VDI.SNAPSHOT_SINGLE or snap_type == VDI.SNAPSHOT_INTERNAL): num_vdis = 1 if (sr_size - reserved) < ((self.size + VDI.VDIMetadataSize( \ vhdutil.VDI_TYPE_VHD, self.size)) * num_vdis): raise xs_errors.XenError('SRNoSpace') newuuid = util.gen_uuid() src = self.path newsrc = os.path.join(self.sr.path, "%s.%s" % (newuuid, self.vdi_type)) newsrcname = "%s.%s" % (newuuid, self.vdi_type) if not self._checkpath(src): raise xs_errors.XenError('VDIUnavailable', \ opterr='VDI %s unavailable %s' % (self.uuid, src)) # wkcfix: multiphase util.start_log_entry(self.sr.path, self.path, args) # We assume the filehandle has been released try: util.ioretry(lambda: os.rename(src, newsrc)) # Create the snapshot under a temporary name, then rename # it afterwards. This avoids a small window where it exists # but is invalid. We do not need to do this for # snap_type == VDI.SNAPSHOT_DOUBLE because dst never existed # before so nobody will try to query it. tmpsrc = "%s.%s" % (src, "new") util.ioretry(lambda: self._snap(tmpsrc, newsrcname)) util.ioretry(lambda: os.rename(tmpsrc, src)) if snap_type == VDI.SNAPSHOT_DOUBLE: util.ioretry(lambda: self._snap(dst, newsrcname)) # mark the original file (in this case, its newsrc) # as hidden so that it does not show up in subsequent scans util.ioretry(lambda: self._mark_hidden(newsrc)) #Verify parent locator field of both children and delete newsrc if unused introduce_parent = True try: srcparent = util.ioretry(lambda: self._query_p_uuid(src)) dstparent = None if snap_type == VDI.SNAPSHOT_DOUBLE: dstparent = util.ioretry(lambda: self._query_p_uuid(dst)) if srcparent != newuuid and \ (snap_type == VDI.SNAPSHOT_SINGLE or \ snap_type == VDI.SNAPSHOT_INTERNAL or \ dstparent != newuuid): util.ioretry(lambda: os.unlink(newsrc)) introduce_parent = False except: pass # Introduce the new VDI records leaf_vdi = None if snap_type == VDI.SNAPSHOT_DOUBLE: leaf_vdi = VDI.VDI(self.sr, dest) # user-visible leaf VDI leaf_vdi.read_only = False leaf_vdi.location = dest leaf_vdi.size = self.size leaf_vdi.utilisation = self.utilisation leaf_vdi.sm_config = {} leaf_vdi.sm_config['vhd-parent'] = dstparent # If the parent is encrypted set the key_hash # for the new snapshot disk vdi_ref = self.sr.srcmd.params['vdi_ref'] sm_config = self.session.xenapi.VDI.get_sm_config(vdi_ref) if "key_hash" in sm_config: leaf_vdi.sm_config['key_hash'] = sm_config['key_hash'] # If we have CBT enabled on the VDI, # set CBT status for the new snapshot disk if cbtlog: leaf_vdi.cbt_enabled = True base_vdi = None if introduce_parent: base_vdi = VDI.VDI(self.sr, newuuid) # readonly parent base_vdi.label = "base copy" base_vdi.read_only = True base_vdi.location = newuuid base_vdi.size = self.size base_vdi.utilisation = self.utilisation base_vdi.sm_config = {} grandparent = util.ioretry(lambda: self._query_p_uuid(newsrc)) if grandparent.find("no parent") == -1: base_vdi.sm_config['vhd-parent'] = grandparent try: if snap_type == VDI.SNAPSHOT_DOUBLE: leaf_vdi_ref = leaf_vdi._db_introduce() util.SMlog("vdi_clone: introduced VDI: %s (%s)" % \ (leaf_vdi_ref,dest)) if introduce_parent: base_vdi_ref = base_vdi._db_introduce() self.session.xenapi.VDI.set_managed(base_vdi_ref, False) util.SMlog("vdi_clone: introduced VDI: %s (%s)" % (base_vdi_ref, newuuid)) vdi_ref = self.sr.srcmd.params['vdi_ref'] sm_config = self.session.xenapi.VDI.get_sm_config(vdi_ref) sm_config['vhd-parent'] = srcparent self.session.xenapi.VDI.set_sm_config(vdi_ref, sm_config) except Exception, e: util.SMlog( "vdi_clone: caught error during VDI.db_introduce: %s" % (str(e))) # Note it's too late to actually clean stuff up here: the base disk has # been marked as deleted already. util.end_log_entry(self.sr.path, self.path, ["error"]) raise except util.CommandException, inst: # XXX: it might be too late if the base disk has been marked as deleted! self._clonecleanup(src, dst, newsrc) util.end_log_entry(self.sr.path, self.path, ["error"]) raise xs_errors.XenError('VDIClone', opterr='VDI clone failed error %d' % inst.code)
def _snapshot(self, snap_type, cbtlog=None, cbt_consistency=None): util.SMlog("FileVDI._snapshot for %s (type %s)" % (self.uuid, snap_type)) args = [] args.append("vdi_clone") args.append(self.sr.uuid) args.append(self.uuid) dest = None dst = None if snap_type == VDI.SNAPSHOT_DOUBLE: dest = util.gen_uuid() dst = os.path.join(self.sr.path, "%s.%s" % (dest,self.vdi_type)) args.append(dest) if self.hidden: raise xs_errors.XenError('VDIClone', opterr='hidden VDI') depth = vhdutil.getDepth(self.path) if depth == -1: raise xs_errors.XenError('VDIUnavailable', \ opterr='failed to get VHD depth') elif depth >= vhdutil.MAX_CHAIN_SIZE: raise xs_errors.XenError('SnapshotChainTooLong') # Test the amount of actual disk space if ENFORCE_VIRT_ALLOC: self.sr._loadvdis() reserved = self.sr.virtual_allocation sr_size = self.sr._getsize() num_vdis = 2 if (snap_type == VDI.SNAPSHOT_SINGLE or snap_type == VDI.SNAPSHOT_INTERNAL): num_vdis = 1 if (sr_size - reserved) < ((self.size + VDI.VDIMetadataSize( \ vhdutil.VDI_TYPE_VHD, self.size)) * num_vdis): raise xs_errors.XenError('SRNoSpace') newuuid = util.gen_uuid() src = self.path newsrc = os.path.join(self.sr.path, "%s.%s" % (newuuid,self.vdi_type)) newsrcname = "%s.%s" % (newuuid,self.vdi_type) if not self._checkpath(src): raise xs_errors.XenError('VDIUnavailable', \ opterr='VDI %s unavailable %s' % (self.uuid, src)) # wkcfix: multiphase util.start_log_entry(self.sr.path, self.path, args) # We assume the filehandle has been released try: util.ioretry(lambda: os.rename(src,newsrc)) # Create the snapshot under a temporary name, then rename # it afterwards. This avoids a small window where it exists # but is invalid. We do not need to do this for # snap_type == VDI.SNAPSHOT_DOUBLE because dst never existed # before so nobody will try to query it. tmpsrc = "%s.%s" % (src, "new") util.ioretry(lambda: self._snap(tmpsrc, newsrcname)) util.ioretry(lambda: os.rename(tmpsrc, src)) if snap_type == VDI.SNAPSHOT_DOUBLE: util.ioretry(lambda: self._snap(dst, newsrcname)) # mark the original file (in this case, its newsrc) # as hidden so that it does not show up in subsequent scans util.ioretry(lambda: self._mark_hidden(newsrc)) #Verify parent locator field of both children and delete newsrc if unused introduce_parent = True try: srcparent = util.ioretry(lambda: self._query_p_uuid(src)) dstparent = None if snap_type == VDI.SNAPSHOT_DOUBLE: dstparent = util.ioretry(lambda: self._query_p_uuid(dst)) if srcparent != newuuid and \ (snap_type == VDI.SNAPSHOT_SINGLE or \ snap_type == VDI.SNAPSHOT_INTERNAL or \ dstparent != newuuid): util.ioretry(lambda: os.unlink(newsrc)) introduce_parent = False except: pass # Introduce the new VDI records leaf_vdi = None if snap_type == VDI.SNAPSHOT_DOUBLE: leaf_vdi = VDI.VDI(self.sr, dest) # user-visible leaf VDI leaf_vdi.read_only = False leaf_vdi.location = dest leaf_vdi.size = self.size leaf_vdi.utilisation = self.utilisation leaf_vdi.sm_config = {} leaf_vdi.sm_config['vhd-parent'] = dstparent # If the parent is encrypted set the key_hash # for the new snapshot disk vdi_ref = self.sr.srcmd.params['vdi_ref'] sm_config = self.session.xenapi.VDI.get_sm_config(vdi_ref) if "key_hash" in sm_config: leaf_vdi.sm_config['key_hash'] = sm_config['key_hash'] # If we have CBT enabled on the VDI, # set CBT status for the new snapshot disk if cbtlog: leaf_vdi.cbt_enabled = True base_vdi = None if introduce_parent: base_vdi = VDI.VDI(self.sr, newuuid) # readonly parent base_vdi.label = "base copy" base_vdi.read_only = True base_vdi.location = newuuid base_vdi.size = self.size base_vdi.utilisation = self.utilisation base_vdi.sm_config = {} grandparent = util.ioretry(lambda: self._query_p_uuid(newsrc)) if grandparent.find("no parent") == -1: base_vdi.sm_config['vhd-parent'] = grandparent try: if snap_type == VDI.SNAPSHOT_DOUBLE: leaf_vdi_ref = leaf_vdi._db_introduce() util.SMlog("vdi_clone: introduced VDI: %s (%s)" % \ (leaf_vdi_ref,dest)) if introduce_parent: base_vdi_ref = base_vdi._db_introduce() self.session.xenapi.VDI.set_managed(base_vdi_ref, False) util.SMlog("vdi_clone: introduced VDI: %s (%s)" % (base_vdi_ref,newuuid)) vdi_ref = self.sr.srcmd.params['vdi_ref'] sm_config = self.session.xenapi.VDI.get_sm_config(vdi_ref) sm_config['vhd-parent'] = srcparent self.session.xenapi.VDI.set_sm_config(vdi_ref, sm_config) except Exception, e: util.SMlog("vdi_clone: caught error during VDI.db_introduce: %s" % (str(e))) # Note it's too late to actually clean stuff up here: the base disk has # been marked as deleted already. util.end_log_entry(self.sr.path, self.path, ["error"]) raise except util.CommandException, inst: # XXX: it might be too late if the base disk has been marked as deleted! self._clonecleanup(src,dst,newsrc) util.end_log_entry(self.sr.path, self.path, ["error"]) raise xs_errors.XenError('VDIClone', opterr='VDI clone failed error %d' % inst.code)
def _snapshot(self, snap_type): util.SMlog("FileVDI._snapshot for %s (type %s)" % (self.uuid, snap_type)) args = [] args.append("vdi_clone") args.append(self.sr.uuid) args.append(self.uuid) dest = None dst = None if snap_type == self.SNAPSHOT_DOUBLE: dest = util.gen_uuid() dst = os.path.join(self.sr.path, "%s.%s" % (dest, self.vdi_type)) args.append(dest) if self.hidden: raise xs_errors.XenError("VDIClone", opterr="hidden VDI") depth = vhdutil.getDepth(self.path) if depth == -1: raise xs_errors.XenError("VDIUnavailable", opterr="failed to get VHD depth") elif depth >= vhdutil.MAX_CHAIN_SIZE: raise xs_errors.XenError("SnapshotChainTooLong") # Test the amount of actual disk space if ENFORCE_VIRT_ALLOC: self.sr._loadvdis() reserved = self.sr.virtual_allocation sr_size = self.sr._getsize() num_vdis = 2 if snap_type == self.SNAPSHOT_SINGLE or snap_type == self.SNAPSHOT_INTERNAL: num_vdis = 1 if (sr_size - reserved) < ((self.size + VDI.VDIMetadataSize(vhdutil.VDI_TYPE_VHD, self.size)) * num_vdis): raise xs_errors.XenError("SRNoSpace") newuuid = util.gen_uuid() src = self.path newsrc = os.path.join(self.sr.path, "%s.%s" % (newuuid, self.vdi_type)) newsrcname = "%s.%s" % (newuuid, self.vdi_type) if not self._checkpath(src): raise xs_errors.XenError("VDIUnavailable", opterr="VDI %s unavailable %s" % (self.uuid, src)) # wkcfix: multiphase util.start_log_entry(self.sr.path, self.path, args) # We assume the filehandle has been released try: try: util.ioretry(lambda: os.rename(src, newsrc)) except util.CommandException, inst: if inst.code != errno.ENOENT: # failed to rename, simply raise error util.end_log_entry(self.sr.path, self.path, ["error"]) raise try: util.ioretry(lambda: self._snap(src, newsrcname)) if snap_type == self.SNAPSHOT_DOUBLE: util.ioretry(lambda: self._snap(dst, newsrcname)) # mark the original file (in this case, its newsrc) # as hidden so that it does not show up in subsequent scans util.ioretry(lambda: self._mark_hidden(newsrc)) except util.CommandException, inst: if inst.code != errno.EIO: raise