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
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
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
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