Пример #1
0
    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
Пример #2
0
    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
Пример #3
0
    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)
Пример #4
0
    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)
Пример #5
0
    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