예제 #1
0
    def put(self):
        if 'note' in self.data:
            # Changing snapshot note instead of rollback (not logging)
            return self._update_note()

        request, vm, snap = self.request, self.vm, self.snap

        if vm.node.status not in vm.node.STATUS_OPERATIONAL:
            raise NodeIsNotOperational

        if vm.locked:
            raise VmIsLocked

        self._check_vm_status()
        self._check_snap_status()
        apiview, detail = self._get_apiview_detail()

        apiview['force'] = bool(ForceSerializer(data=self.data, default=True))

        if not apiview['force']:
            snaplast = Snapshot.objects.only('id').filter(
                vm=vm, disk_id=snap.disk_id).order_by('-id')[0]
            if snap.id != snaplast.id:
                raise ExpectationFailed('VM has more recent snapshots')

        if vm.status != vm.STOPPED:
            raise VmIsNotOperational('VM is not stopped')

        if vm.tasks:
            raise VmHasPendingTasks

        msg = LOG_SNAP_UPDATE
        lock = self.LOCK % (vm.uuid, snap.disk_id)
        cmd = 'esnapshot rollback "%s@%s" 2>&1' % (self.zfs_filesystem,
                                                   snap.zfs_name)
        vm.set_notready()
        tid, err = execute(request,
                           vm.owner.id,
                           cmd,
                           meta=snap_meta(vm, msg, apiview, detail),
                           lock=lock,
                           callback=snap_callback(vm, snap),
                           queue=vm.node.fast_queue)

        if err:
            vm.revert_notready()
            return FailureTaskResponse(request, err, vm=vm)
        else:
            snap.save_status(snap.ROLLBACK)
            return TaskResponse(request,
                                tid,
                                msg=msg,
                                vm=vm,
                                api_view=apiview,
                                detail=detail,
                                data=self.data)
예제 #2
0
    def post(self):
        self._check_vm_status()
        apiview, detail = self._get_apiview_detail()
        request, vm, snap = self.request, self.vm, self.snap

        snap.status = snap.PENDING
        snap.define_id = self.snap_define_id
        snap.type = self.snaptype
        ser = SnapshotSerializer(request, snap, data=self.data)
        fsfreeze = ''

        if not ser.is_valid():
            return FailureTaskResponse(request, ser.errors, vm=vm)

        if vm.is_hvm() and self.data.get('fsfreeze', False):
            qga_socket = vm.qga_socket_path

            if qga_socket:
                snap.fsfreeze = True
                if vm.status != vm.STOPPED:
                    fsfreeze = '"%s"' % qga_socket

        self._check_snap_limit()
        self._check_snap_size_limit()  # Issue #chili-848
        self._check_snap_dc_size_limit()  # Issue #chili-848
        snap.zpool = vm.node.nodestorage_set.get(zpool=self.zpool)
        snap.save()
        detail += ', type=%s, fsfreeze=%s' % (self.snaptype, str(
            snap.fsfreeze).lower())
        msg = LOG_SNAP_CREATE
        lock = self.LOCK % (vm.uuid, snap.disk_id)
        cmd = 'esnapshot create "%s@%s" "es:snapname=%s" %s 2>&1' % (
            self.zfs_filesystem, snap.zfs_name, snap.name, fsfreeze)
        tid, err = execute(request,
                           vm.owner.id,
                           cmd,
                           meta=snap_meta(vm, msg, apiview, detail),
                           lock=lock,
                           callback=snap_callback(vm, snap),
                           queue=vm.node.fast_queue,
                           tt=self.tt)

        if err:
            snap.delete()
            return FailureTaskResponse(request, err, vm=vm)
        else:
            return TaskResponse(request,
                                tid,
                                msg=msg,
                                vm=vm,
                                api_view=apiview,
                                detail=detail,
                                data=self.data)
예제 #3
0
    def delete(self):
        """Delete multiple snapshots"""
        request, data, vm = self.request, self.data, self.vm

        disk_id, real_disk_id, zfs_filesystem = get_disk_id(request, vm, data)
        # Parse data['snapnames']
        snaps, __ = get_snapshots(request, vm, real_disk_id, data)

        self._check_vm_status()

        snaps_lost = snaps.filter(status=Snapshot.LOST)
        msg = LOG_SNAPS_DELETE

        if snaps_lost:
            _result = {'message': 'Snapshots successfully deleted from DB'}
            _detail = "snapnames='%s', disk_id=%s" % (','.join(i.name for i in snaps_lost), disk_id)
            snaps_lost.delete()
            res = SuccessTaskResponse(request, _result, msg=msg, vm=vm, detail=_detail)
            snaps = snaps.filter(status=Snapshot.OK)  # Work with OK snapshots from now on

            if not snaps:
                return res

        elif any(i.status != Snapshot.OK for i in snaps):
            raise ExpectationFailed('VM snapshot status is not OK')

        # Task type (a = automatic, e = manual)
        if getattr(request, 'define_id', None):
            tt = TT_AUTO
        else:
            tt = TT_EXEC

        snapnames = [i.name for i in snaps]
        _apiview_ = {'view': 'vm_snapshot_list', 'method': request.method,
                     'hostname': vm.hostname, 'disk_id': disk_id, 'snapnames': snapnames}
        _detail_ = "snapnames='%s', disk_id=%s" % (','.join(snapnames), disk_id)

        snap_ids = [snap.id for snap in snaps]
        zfs_names = ','.join([snap.zfs_name for snap in snaps])
        lock = self.LOCK % (vm.uuid, real_disk_id)
        cmd = 'esnapshot destroy "%s@%s" 2>&1' % (zfs_filesystem, zfs_names)
        callback = ('api.vm.snapshot.tasks.vm_snapshot_list_cb', {'vm_uuid': vm.uuid, 'snap_ids': snap_ids})

        tid, err = execute(request, vm.owner.id, cmd, meta=snap_meta(vm, msg, _apiview_, _detail_), lock=lock,
                           callback=callback, queue=vm.node.fast_queue, tt=tt)
        if err:
            return FailureTaskResponse(request, err, vm=vm)
        else:
            snaps.update(status=Snapshot.PENDING)
            return TaskResponse(request, tid, msg=msg, vm=vm, api_view=_apiview_, detail=_detail_, data=self.data)
예제 #4
0
    def delete(self):
        self._check_vm_status()
        self._check_snap_status(lost_ok=True)
        request, vm, snap = self.request, self.vm, self.snap
        apiview, detail = self._get_apiview_detail()
        msg = LOG_SNAP_DELETE

        if snap.status == Snapshot.LOST:
            snap.delete()
            res = {'message': 'Snapshot successfully deleted from DB'}
            return SuccessTaskResponse(request,
                                       res,
                                       msg=msg,
                                       vm=vm,
                                       detail=detail)

        SnapshotSerializer(request, snap)
        lock = self.LOCK % (vm.uuid, snap.disk_id)
        cmd = 'esnapshot destroy "%s@%s" 2>&1' % (self.zfs_filesystem,
                                                  snap.zfs_name)
        tid, err = execute(request,
                           vm.owner.id,
                           cmd,
                           meta=snap_meta(vm, msg, apiview, detail),
                           lock=lock,
                           callback=snap_callback(vm, snap),
                           queue=vm.node.fast_queue,
                           tt=self.tt)

        if err:
            return FailureTaskResponse(request, err, vm=vm)
        else:
            snap.save_status(snap.PENDING)
            return TaskResponse(request,
                                tid,
                                msg=msg,
                                vm=vm,
                                api_view=apiview,
                                detail=detail,
                                data=self.data)
예제 #5
0
    def put(self):
        if 'note' in self.data:
            # Changing snapshot note instead of rollback (not logging)
            return self._update_note()

        request, vm, snap = self.request, self.vm, self.snap

        ser = SnapshotRestoreSerializer(request, vm, data=self.data)
        if not ser.is_valid():
            return FailureTaskResponse(self.request, ser.errors)

        target_vm, target_vm_disk_id = ser.target_vm, ser.target_vm_disk_id

        if vm.node.status not in vm.node.STATUS_OPERATIONAL:
            raise NodeIsNotOperational

        if target_vm.locked:
            raise VmIsLocked

        if target_vm != vm:
            if target_vm.node.status not in target_vm.node.STATUS_OPERATIONAL:
                raise NodeIsNotOperational

            self._check_vm_status(vm=target_vm)

            if not vm.has_compatible_brand(target_vm.brand):
                raise PreconditionRequired('VM brand mismatch')

            source_disk = vm.json_active_get_disks()[self.disk_id - 1]
            target_disk = target_vm.json_active_get_disks()[target_vm_disk_id -
                                                            1]

            if target_disk['size'] != source_disk['size']:
                raise PreconditionRequired('Disk size mismatch')

        self._check_vm_status()
        self._check_snap_status()
        apiview, detail = self._get_apiview_detail()
        apiview['force'] = ser.data['force']

        if target_vm != vm:
            detail += ", source_hostname='%s', target_hostname='%s', target_disk_id=%s" % (
                vm.hostname, target_vm.hostname, target_vm_disk_id)
            apiview['source_hostname'] = vm.hostname
            apiview['target_hostname'] = target_vm.hostname
            apiview['target_disk_id'] = target_vm_disk_id

            if not apiview['force']:
                if Snapshot.objects.only('id').filter(
                        vm=target_vm,
                        disk_id=ser.target_vm_real_disk_id).exists():
                    raise ExpectationFailed('Target VM has snapshots')

        elif not apiview['force']:
            snaplast = Snapshot.objects.only('id').filter(
                vm=vm, disk_id=snap.disk_id).order_by('-id')[0]
            if snap.id != snaplast.id:
                raise ExpectationFailed('VM has more recent snapshots')

        if target_vm.status != vm.STOPPED:
            raise VmIsNotOperational('VM is not stopped')

        if target_vm.tasks:
            raise VmHasPendingTasks

        msg = LOG_SNAP_UPDATE
        lock = self.LOCK % (vm.uuid, snap.disk_id)

        if target_vm == vm:
            cmd = 'esnapshot rollback "%s@%s" 2>&1' % (self.zfs_filesystem,
                                                       snap.zfs_name)
        else:
            cmd = 'esbackup snap-restore -s %s@%s -d %s' % (
                self.zfs_filesystem, snap.zfs_name,
                ser.target_vm_disk_zfs_filesystem)
            if vm.node != target_vm.node:
                cmd += ' -H %s' % target_vm.node.address

            vm.set_notready()

        target_vm.set_notready()
        tid, err = execute(request,
                           target_vm.owner.id,
                           cmd,
                           meta=snap_meta(target_vm, msg, apiview, detail),
                           lock=lock,
                           callback=snap_callback(target_vm, snap),
                           queue=vm.node.fast_queue)

        if err:
            target_vm.revert_notready()
            if vm != target_vm:
                vm.revert_notready()
            return FailureTaskResponse(request, err, vm=target_vm)
        else:
            snap.save_status(snap.ROLLBACK)
            return TaskResponse(request,
                                tid,
                                msg=msg,
                                vm=target_vm,
                                api_view=apiview,
                                detail=detail,
                                data=self.data)