Beispiel #1
0
def get_disk_id(request, vm, data, key='disk_id', default=1):
    """Get disk_id from data and return additional disk information"""
    disk_id = data.get(key, default)
    # noinspection PyBroadException
    try:
        disk_id = int(disk_id)
        if not disk_id > 0:
            raise ValueError
        disk = vm.json_active_get_disks()[disk_id - 1]
        zfs_filesystem = disk['zfs_filesystem']
        real_disk_id = Snapshot.get_real_disk_id(disk)
    except:
        raise InvalidInput('Invalid %s' % key)

    return disk_id, real_disk_id, zfs_filesystem
Beispiel #2
0
def vm_delete_snapshots_of_removed_disks(vm):
    """
    This helper function deletes snapshots for VM with changing disk IDs. Bug #chili-363
    ++ Bug #chili-220 - removing snapshot and backup definitions for removed disks.
    """
    removed_disk_ids = [
        Snapshot.get_real_disk_id(i)
        for i in vm.create_json_update_disks().get('remove_disks', [])
    ]
    if removed_disk_ids:
        Snapshot.objects.filter(vm=vm, disk_id__in=removed_disk_ids).delete()
        SnapshotDefine.objects.filter(vm=vm,
                                      disk_id__in=removed_disk_ids).delete()
        Backup.objects.filter(vm=vm, disk_id__in=removed_disk_ids,
                              last=True).update(last=False)
        BackupDefine.objects.filter(vm=vm,
                                    disk_id__in=removed_disk_ids).delete()
    return removed_disk_ids
Beispiel #3
0
def vm_backup_cb(result, task_id, vm_uuid=None, node_uuid=None, bkp_id=None):
    """
    A callback function for api.vm.backup.views.vm_backup.
    """
    bkp = Backup.objects.select_related('vm', 'dc').get(id=bkp_id)
    action = result['meta']['apiview']['method']
    json = result.pop('json', '')
    message = result.get('message', json)
    data = {}
    obj_id = vm_uuid or node_uuid
    success = False

    try:  # save json from esbackup
        data = bkp.json.load(json)
    except Exception as e:
        logger.error(
            'Could not parse json output from %s vm_backup(%s, %s). Error: %s',
            action, obj_id, bkp, e)
        result['detail'] = message or json
    else:
        success = data.get('success', False)
        try:
            result['detail'] = _vm_backup_cb_detail(data)
        except Exception as ex:
            logger.exception(ex)
            result['detail'] = json.replace('\n', '')

    msg = data.get('msg', message)

    if action == 'PUT':
        vm = Vm.objects.get(uuid=vm_uuid)
        obj = vm
    else:
        vm = None
        obj = bkp.vm or bkp.node

        if bkp.type == Backup.DATASET:
            if action == 'POST':
                _vm_backup_update_snapshots(
                    data, 'new_name',
                    'file_path')  # Update file_path of archived backups
                _vm_backup_deleted_last_snapshot_names(
                    data)  # Remove last flag from deleted snapshots

            elif action == 'DELETE':
                _vm_backup_update_snapshots(
                    data, 'written',
                    'size')  # Update size of remaining backups
                _vm_backup_deleted_last_snapshot_names(
                    data)  # Remove last flag from deleted snapshots

    if result['returncode'] == 0 and success:
        if action == 'POST':
            if bkp.type == Backup.DATASET:
                bkp.file_path = data.get('backup_snapshot', '')
                bkp.size = data.get('backup_snapshot_size', None)

                if data.get('last_snapshot_name', None):
                    bkp.last = True
            else:
                bkp.file_path = data.get('file', '')
                bkp.size = data.get('size', None)
                bkp.checksum = data.get('checksum', '')

            result['message'] = 'Backup successfully created'

            if bkp.fsfreeze:
                if 'freeze failed' in msg:
                    bkp.fsfreeze = False
                    result['message'] += ' (filesystem freeze failed)'
                    MonitoringBackend.vm_send_alert(
                        bkp.vm,
                        'Backup %s of server %s@disk-%s was created, but filesystem freeze '
                        'failed.' %
                        (bkp.name, bkp.vm.hostname, bkp.array_disk_id),
                        priority=MonitoringBackend.WARNING)

            bkp.manifest_path = data.get('metadata_file', '')
            bkp.time = data.get('time_elapsed', None)
            bkp.status = bkp.OK
            bkp.save()

            if bkp.define and bkp.define.retention:  # Retention - delete oldest snapshot
                assert bkp.vm == bkp.define.vm
                assert bkp.disk_id == bkp.define.disk_id
                from api.vm.backup.views import vm_backup_list
                _delete_oldest(Backup, bkp.define, vm_backup_list, 'bkpnames',
                               task_id, LOG_BKPS_DELETE)

            bkp.update_zpool_resources()

        elif action == 'PUT':
            bkp.status = bkp.OK
            bkp.save_status()

            if result['meta']['apiview']['force']:  # Remove all snapshots
                disk = vm.json_active_get_disks()[
                    result['meta']['apiview']['target_disk_id'] - 1]
                real_disk_id = Snapshot.get_real_disk_id(disk)
                # TODO: check indexes
                Snapshot.objects.filter(vm=vm, disk_id=real_disk_id).delete()

            vm.revert_notready()
            result['message'] = 'Backup successfully restored'

        elif action == 'DELETE':
            bkp.delete()
            bkp.update_zpool_resources()
            result['message'] = 'Backup successfully deleted'

    else:
        _vm_backup_cb_failed(result, task_id, bkp, action,
                             vm=vm)  # Delete backup or update backup status
        logger.error(
            'Found nonzero returncode in result from %s vm_backup(%s, %s). Error: %s',
            action, obj_id, bkp, msg)
        raise TaskException(result,
                            'Got bad return code (%s). Error: %s' %
                            (result['returncode'], msg),
                            bkp=bkp)

    task_log_cb_success(result, task_id, obj=obj, **result['meta'])
    return result
Beispiel #4
0
def vm_snapshot_cb(result, task_id, vm_uuid=None, snap_id=None):
    """
    A callback function for api.vm.snapshot.views.vm_snapshot.
    """
    snap = Snapshot.objects.select_related('vm').get(id=snap_id)
    vm = Vm.objects.get(uuid=vm_uuid)
    action = result['meta']['apiview']['method']
    msg = result.get('message', '')

    if result['returncode'] == 0:
        if msg:
            # noinspection PyBroadException
            try:
                result['detail'] = _vm_snapshot_cb_detail(json.loads(msg))
            except Exception:
                result['detail'] = 'msg=' + to_string(msg)
        else:
            result['detail'] = ''

        if action == 'POST':
            assert vm == snap.vm
            snap.status = snap.OK
            result['message'] = 'Snapshot successfully created'

            if snap.fsfreeze:
                if 'freeze failed' in msg:
                    snap.fsfreeze = False
                    result['message'] += ' (filesystem freeze failed)'
                    MonitoringBackend.vm_send_alert(
                        vm,
                        'Snapshot %s of server %s@disk-%s was created, but filesystem '
                        'freeze failed.' %
                        (snap.name, vm.hostname, snap.array_disk_id),
                        priority=MonitoringBackend.WARNING)

            snap.save(update_fields=('status', 'fsfreeze'))

            if snap.define and snap.define.retention:  # Retention - delete oldest snapshot
                assert vm == snap.define.vm
                assert snap.disk_id == snap.define.disk_id
                from api.vm.snapshot.views import vm_snapshot_list
                _delete_oldest(Snapshot, snap.define, vm_snapshot_list,
                               'snapnames', task_id, LOG_SNAPS_DELETE)

        elif action == 'PUT':
            if vm != snap.vm:
                snap.vm.revert_notready()
            vm.revert_notready()
            snap.status = snap.OK
            snap.save_status()

            if result['meta']['apiview']['force']:
                if snap.vm == vm:
                    # TODO: check indexes
                    Snapshot.objects.filter(vm=vm,
                                            disk_id=snap.disk_id,
                                            id__gt=snap.id).delete()
                else:
                    disk = vm.json_active_get_disks()[
                        result['meta']['apiview']['target_disk_id'] - 1]
                    real_disk_id = Snapshot.get_real_disk_id(disk)
                    # TODO: check indexes
                    Snapshot.objects.filter(vm=vm,
                                            disk_id=real_disk_id).delete()

            result['message'] = 'Snapshot successfully restored'

        elif action == 'DELETE':
            assert vm == snap.vm
            snap.delete()
            result['message'] = 'Snapshot successfully deleted'

    else:
        _vm_snapshot_cb_failed(
            result, task_id, snap, action,
            vm=vm)  # Delete snapshot or update snapshot status
        logger.error(
            'Found nonzero returncode in result from %s vm_snapshot(%s, %s). Error: %s',
            action, vm_uuid, snap, msg)
        raise TaskException(result,
                            'Got bad return code (%s). Error: %s' %
                            (result['returncode'], msg),
                            snap=snap)

    task_log_cb_success(result, task_id, vm=vm, **result['meta'])
    return result