From nobody Mon Feb 9 11:59:06 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1504022063362565.9346444499238; Tue, 29 Aug 2017 08:54:23 -0700 (PDT) Received: from localhost ([::1]:45621 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dmiqK-0008Pa-Kp for importer@patchew.org; Tue, 29 Aug 2017 11:54:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53887) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dmimd-0005mF-5C for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dmimZ-0000E7-AM for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:31 -0400 Received: from research.iiit.ac.in ([196.12.53.8]:58866) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dmimY-0000BB-HA for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:27 -0400 Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id C94CA742041; Tue, 29 Aug 2017 21:20:23 +0530 (IST) Received: from research.iiit.ac.in ([127.0.0.1]) by localhost (research.iiit.ac.in [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id le1xU37KPZx4; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id BC9CC744793; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from research.iiit.ac.in ([127.0.0.1]) by localhost (research.iiit.ac.in [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id AKwk19Xl4_Zt; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from ishani-Inspiron-5558.iiit.ac.in (unknown [10.2.20.52]) by research.iiit.ac.in (Postfix) with ESMTPSA id 9FFA5741EE1; Tue, 29 Aug 2017 21:20:20 +0530 (IST) DKIM-Filter: OpenDKIM Filter v2.9.2 research.iiit.ac.in BC9CC744793 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=research.iiit.ac.in; s=4E8815E6-5B55-11E4-B758-8D4964374E96; t=1504021820; bh=AMkb7Fx0BKG/W2U+tN7zK8ch7HNvbn3MdBTx/Fa42Bk=; h=From:To:Subject:Date:Message-Id; b=yUIa9ZakMg6b30Csikotf9BPYH/blovSQwvzTCgAcjBusb5LlzrnYQqZSsbquoPz4 JNRtlM7ZTu5bJ4m2Q677OUO6vzeWUnokjdIIoOTPs5Xcw5bLvpSNL0UN6yj70pZcRO Hs4kDTqZooVIPi7Ks9nf1DlqBeVi/u7PHEGGC2hw= X-Virus-Scanned: amavisd-new at research.iiit.ac.in From: Ishani Chugh To: qemu-devel@nongnu.org Date: Tue, 29 Aug 2017 21:20:16 +0530 Message-Id: <1504021818-12128-2-git-send-email-chugh.ishani@research.iiit.ac.in> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1504021818-12128-1-git-send-email-chugh.ishani@research.iiit.ac.in> References: <1504021818-12128-1-git-send-email-chugh.ishani@research.iiit.ac.in> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 196.12.53.8 Subject: [Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ishani Chugh , jsnow@redhat.com, stefanha@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" qemu-backup will be a command-line tool for performing full and=20 incremental disk backups on running VMs. It is intended as a reference implementation for management stack and backup developers to see QEMU's backup features in action. The tool writes details of guest in a configuration file and the data is retrieved from the file while creating a backup. The location of config file can be set as an environment variable QEMU_BACKUP_CONFIG. The usage is as follows: Add a guest python qemu-backup.py guest add --guest --qmp Add a drive for backup in a specified guest python qemu-backup.py drive add --guest --id [--tar= get ] Create backup of the added drives: python qemu-backup.py backup --guest List all guest configs in configuration file: python qemu-backup.py guest list Restore operation python qemu-backup.py restore --guest Remove a guest python qemu-backup.py guest remove --guest Signed-off-by: Ishani Chugh --- contrib/backup/qemu-backup.py | 335 ++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 335 insertions(+) create mode 100644 contrib/backup/qemu-backup.py diff --git a/contrib/backup/qemu-backup.py b/contrib/backup/qemu-backup.py new file mode 100644 index 0000000..c8032de --- /dev/null +++ b/contrib/backup/qemu-backup.py @@ -0,0 +1,335 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2017 Ishani Chugh +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +""" +This file is an implementation of backup tool +""" +from __future__ import print_function +from argparse import ArgumentParser +import os +import errno +from socket import error as socket_error +try: + import configparser +except ImportError: + import ConfigParser as configparser +import sys +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', + 'scripts', 'qmp')) +from qmp import QEMUMonitorProtocol + + +class BackupTool(object): + """BackupTool Class""" + def __init__(self, config_file=3Dos.path.expanduser('~') + + '/.config/qemu/qemu-backup-config'): + if "QEMU_BACKUP_CONFIG" in os.environ: + self.config_file =3D os.environ["QEMU_BACKUP_CONFIG"] + else: + self.config_file =3D config_file + try: + if not os.path.isdir(os.path.dirname(self.config_file)): + os.makedirs(os.path.dirname(self.config_file)) + except: + print("Cannot create config directory", file=3Dsys.stderr) + sys.exit(1) + self.config =3D configparser.ConfigParser() + self.config.read(self.config_file) + + def write_config(self): + """ + Writes configuration to ini file. + """ + config_file =3D open(self.config_file + ".tmp", 'w') + self.config.write(config_file) + config_file.flush() + os.fsync(config_file.fileno()) + config_file.close() + os.rename(self.config_file + ".tmp", self.config_file) + + def get_socket_address(self, socket_address): + """ + Return Socket address in form of string or tuple + """ + if socket_address.startswith('tcp'): + return (socket_address.split(':')[1], + int(socket_address.split(':')[2])) + return socket_address.split(':', 2)[1] + + def _full_backup(self, guest_name): + """ + Performs full backup of guest + """ + if guest_name not in self.config.sections(): + print("Cannot find specified guest", file=3Dsys.stderr) + sys.exit(1) + + self.verify_guest_running(guest_name) + connection =3D QEMUMonitorProtocol( + self.get_socket_address( + self.config[guest_name]['qmp'= ])) + connection.connect() + cmd =3D {"execute": "transaction", "arguments": {"actions": []}} + drive_list =3D [] + for key in self.config[guest_name]: + if key.startswith("drive_"): + drive =3D key[len('drive_'):] + drive_list.append(drive) + target =3D self.config[guest_name][key] + sub_cmd =3D {"type": "drive-backup", "data": {"device": dr= ive, + "target": targ= et, + "sync": "full"= }} + cmd['arguments']['actions'].append(sub_cmd) + qmp_return =3D connection.cmd_obj(cmd) + if 'error' in qmp_return: + print(qmp_return['error']['desc'], file=3Dsys.stderr) + sys.exit(1) + print("Backup Started") + while len(drive_list) !=3D 0: + event =3D connection.pull_event(wait=3DTrue) + if event['event'] =3D=3D 'SHUTDOWN': + print("The guest was SHUT DOWN", file=3Dsys.stderr) + sys.exit(1) + + if event['event'] =3D=3D 'BLOCK_JOB_COMPLETED': + if event['data']['device'] in drive_list and \ + event['data']['type'] =3D=3D 'backup': + print("*" + event['data']['device']) + drive_list.remove(event['data']['device']) + + if event['event'] =3D=3D 'BLOCK_JOB_ERROR': + if event['data']['device'] in drive_list and \ + event['data']['type'] =3D=3D 'backup': + print(event['data']['device'] + " Backup Failed", + file=3Dsys.stderr) + drive_list.remove(event['data']['device']) + print("Backup Complete") + + def _drive_add(self, drive_id, guest_name, target=3DNone): + """ + Adds drive for backup + """ + if target is None: + target =3D os.path.abspath(drive_id) + + if os.path.isdir(os.path.dirname(target)) is False: + print("Cannot find target directory", file=3Dsys.stderr) + sys.exit(1) + + if guest_name not in self.config.sections(): + print("Cannot find specified guest", file=3Dsys.stderr) + sys.exit(1) + + if "drive_" + drive_id in self.config[guest_name]: + print("Drive already marked for backup", file=3Dsys.stderr) + sys.exit(1) + + self.verify_guest_running(guest_name) + + connection =3D QEMUMonitorProtocol( + self.get_socket_address( + self.config[guest_name]['qmp'= ])) + connection.connect() + cmd =3D {'execute': 'query-block'} + returned_json =3D connection.cmd_obj(cmd) + device_present =3D False + for device in returned_json['return']: + if device['device'] =3D=3D drive_id: + device_present =3D True + break + + if not device_present: + print("No such drive in guest", file=3Dsys.stderr) + sys.exit(1) + + drive_id =3D "drive_" + drive_id + for d_id in self.config[guest_name]: + if self.config[guest_name][d_id] =3D=3D target: + print("Please choose different target", file=3Dsys.stderr) + sys.exit(1) + self.config.set(guest_name, drive_id, target) + self.write_config() + print("Successfully Added Drive") + + def verify_guest_running(self, guest_name): + """ + Checks whether specified guest is running or not + """ + socket_address =3D self.config.get(guest_name, 'qmp') + try: + connection =3D QEMUMonitorProtocol(self.get_socket_address( + socket_address)) + connection.connect() + except socket_error: + if socket_error.errno !=3D errno.ECONNREFUSED: + print("Connection to guest refused", file=3Dsys.stderr) + sys.exit(1) + + def _guest_add(self, guest_name, socket_address): + """ + Adds a guest to the config file + """ + if guest_name in self.config.sections(): + print("ID already exists. Please choose a different guestname", + file=3Dsys.stderr) + sys.exit(1) + self.config[guest_name] =3D {'qmp': socket_address} + self.verify_guest_running(guest_name) + self.write_config() + print("Successfully Added Guest") + + def _guest_remove(self, guest_name): + """ + Removes a guest from config file + """ + if guest_name not in self.config.sections(): + print("Guest Not present", file=3Dsys.stderr) + sys.exit(1) + self.config.remove_section(guest_name) + print("Guest successfully deleted") + + def _restore(self, guest_name): + """ + Prints Steps to perform restore operation + """ + if guest_name not in self.config.sections(): + print("Cannot find specified guest", file=3Dsys.stderr) + sys.exit(1) + + self.verify_guest_running(guest_name) + connection =3D QEMUMonitorProtocol( + self.get_socket_address( + self.config[guest_name]['qmp'= ])) + connection.connect() + print("To perform restore:") + print("Shut down guest") + for key in self.config[guest_name]: + if key.startswith("drive_"): + drive =3D key[len('drive_'):] + target =3D self.config[guest_name][key] + cmd =3D {'execute': 'query-block'} + returned_json =3D connection.cmd_obj(cmd) + device_present =3D False + for device in returned_json['return']: + if device['device'] =3D=3D drive: + device_present =3D True + location =3D device['inserted']['image']['filename= '] + print("Replace " + location + " By " + target) + + if not device_present: + print("No such drive in guest", file=3Dsys.stderr) + sys.exit(1) + + def guest_remove_wrapper(self, args): + """ + Wrapper for _guest_remove method. + """ + guest_name =3D args.guest + self._guest_remove(guest_name) + self.write_config() + + def list(self, args): + """ + Prints guests present in Config file + """ + for guest_name in self.config.sections(): + print(guest_name) + + def guest_add_wrapper(self, args): + """ + Wrapper for _quest_add method + """ + self._guest_add(args.guest, args.qmp) + + def drive_add_wrapper(self, args): + """ + Wrapper for _drive_add method + """ + self._drive_add(args.id, args.guest, args.target) + + def fullbackup_wrapper(self, args): + """ + Wrapper for _full_backup method + """ + self._full_backup(args.guest) + + def restore_wrapper(self, args): + """ + Wrapper for restore + """ + self._restore(args.guest) + + +def main(): + backup_tool =3D BackupTool() + parser =3D ArgumentParser() + subparsers =3D parser.add_subparsers(title=3D'Subcommands', + description=3D'Valid Subcommands', + help=3D'Subcommand help') + guest_parser =3D subparsers.add_parser('guest', help=3D'Adds or \ + removes and lists guest= (s)') + guest_subparsers =3D guest_parser.add_subparsers(title=3D'Guest Subpar= ser') + guest_list_parser =3D guest_subparsers.add_parser('list', + help=3D'Lists all gues= ts') + guest_list_parser.set_defaults(func=3Dbackup_tool.list) + + guest_add_parser =3D guest_subparsers.add_parser('add', help=3D'Adds a= guest') + guest_add_parser.add_argument('--guest', action=3D'store', type=3Dstr, + help=3D'Name of the guest') + guest_add_parser.add_argument('--qmp', action=3D'store', type=3Dstr, + help=3D'Path of socket') + guest_add_parser.set_defaults(func=3Dbackup_tool.guest_add_wrapper) + + guest_remove_parser =3D guest_subparsers.add_parser('remove', + help=3D'removes a gu= est') + guest_remove_parser.add_argument('--guest', action=3D'store', type=3Ds= tr, + help=3D'Name of the guest') + guest_remove_parser.set_defaults(func=3Dbackup_tool.guest_remove_wrapp= er) + + drive_parser =3D subparsers.add_parser('drive', + help=3D'Adds drive(s) for backup') + drive_subparsers =3D drive_parser.add_subparsers(title=3D'Add subparse= r', + description=3D'Drive \ + subparser') + drive_add_parser =3D drive_subparsers.add_parser('add', + help=3D'Adds new \ + drive for backup') + drive_add_parser.add_argument('--guest', action=3D'store', + type=3Dstr, help=3D'Name of the guest') + drive_add_parser.add_argument('--id', action=3D'store', + type=3Dstr, help=3D'Drive ID') + drive_add_parser.add_argument('--target', nargs=3D'?', + default=3DNone, help=3D'Destination path= ') + drive_add_parser.set_defaults(func=3Dbackup_tool.drive_add_wrapper) + + backup_parser =3D subparsers.add_parser('backup', help=3D'Creates back= up') + backup_parser.add_argument('--guest', action=3D'store', + type=3Dstr, help=3D'Name of the guest') + backup_parser.set_defaults(func=3Dbackup_tool.fullbackup_wrapper) + + backup_parser =3D subparsers.add_parser('restore', help=3D'Restores dr= ives') + backup_parser.add_argument('--guest', action=3D'store', + type=3Dstr, help=3D'Name of the guest') + backup_parser.set_defaults(func=3Dbackup_tool.restore_wrapper) + + args =3D parser.parse_args() + args.func(args) + +if __name__ =3D=3D '__main__': + main() --=20 2.7.4 From nobody Mon Feb 9 11:59:06 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1504021935014996.5989917015191; Tue, 29 Aug 2017 08:52:15 -0700 (PDT) Received: from localhost ([::1]:45616 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dmioG-0006oR-P8 for importer@patchew.org; Tue, 29 Aug 2017 11:52:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53888) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dmimd-0005mG-5t for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dmimZ-0000Dp-8Z for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:31 -0400 Received: from research.iiit.ac.in ([196.12.53.8]:58842) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dmimY-0000AW-H7 for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:27 -0400 Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id D4050741F5E; Tue, 29 Aug 2017 21:20:22 +0530 (IST) Received: from research.iiit.ac.in ([127.0.0.1]) by localhost (research.iiit.ac.in [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id vVg3KIRN_7kv; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id BE07D744E29; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from research.iiit.ac.in ([127.0.0.1]) by localhost (research.iiit.ac.in [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id sMkg4oW4x1kJ; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from ishani-Inspiron-5558.iiit.ac.in (unknown [10.2.20.52]) by research.iiit.ac.in (Postfix) with ESMTPSA id A56A8741F5E; Tue, 29 Aug 2017 21:20:20 +0530 (IST) DKIM-Filter: OpenDKIM Filter v2.9.2 research.iiit.ac.in BE07D744E29 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=research.iiit.ac.in; s=4E8815E6-5B55-11E4-B758-8D4964374E96; t=1504021820; bh=pWeA3Y/1pyoBgrFtKC4VvbbY/tFUz1yYfP37FIAdKqc=; h=From:To:Subject:Date:Message-Id; b=kxwM9lOHY3wfGkSYLgmvwo/UuxLpVlEmlTuo95rbQA43yfyodyOn+gVi2lu34tnCr sGt7Eu8q3s5ZQ7WXc44tcHAmp0Axl21SQjpM2GpFOqYmTnGvC25VPhP0NUChtZE4fq yG2Rrvm5aOoA27wbkgO6rFwYMci8vYaGVzYaNu28= X-Virus-Scanned: amavisd-new at research.iiit.ac.in From: Ishani Chugh To: qemu-devel@nongnu.org Date: Tue, 29 Aug 2017 21:20:17 +0530 Message-Id: <1504021818-12128-3-git-send-email-chugh.ishani@research.iiit.ac.in> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1504021818-12128-1-git-send-email-chugh.ishani@research.iiit.ac.in> References: <1504021818-12128-1-git-send-email-chugh.ishani@research.iiit.ac.in> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 196.12.53.8 Subject: [Qemu-devel] [PATCH 2/3] Test for full Backup X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ishani Chugh , jsnow@redhat.com, stefanha@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch is the test for full backup implementation in Backup tool. The test employs two basic substests: 1) Backing up an empty guest and comparing it with base image. 2) Writing a pattern to the guest, creating backup and comparing with the base image. Signed-off-by: Ishani Chugh --- tests/qemu-iotests/191 | 86 ++++++++++++++++++++++++++++++++++++++++++= ++++ tests/qemu-iotests/191.out | 35 +++++++++++++++++++ tests/qemu-iotests/group | 2 ++ 3 files changed, 123 insertions(+) create mode 100755 tests/qemu-iotests/191 create mode 100644 tests/qemu-iotests/191.out diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191 new file mode 100755 index 0000000..16988d8 --- /dev/null +++ b/tests/qemu-iotests/191 @@ -0,0 +1,86 @@ +#!/bin/bash +# +# Test full backup functionality of qemu-backup tool +# +# Copyright (C) 2017 Ishani Chugh +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# creator +owner=3Dchugh.ishani@research.iiit.ac.in + +seq=3D`basename $0` +echo "QA output created by $seq" + +here=3D`pwd` +status=3D1 # failure is the default! + + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +_cleanup() +{ + rm -f "$TEST_DIR"/virtio0 + rm -f "$CONFIG_FILE" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +CONFIG_FILE=3D"$TEST_DIR"/backup-config +SOCKET=3Dunix:"$TEST_DIR"/backup_socket +size=3D128M + +_make_test_img "$size" +export QEMU_BACKUP_CONFIG=3D"$CONFIG_FILE" +qemu_comm_method=3D"monitor" +echo +_launch_qemu -drive if=3Dvirtio,file=3D"$TEST_IMG" -qmp "$SOCKET",server,n= owait +$PYTHON ../../contrib/backup/qemu-backup.py guest add --guest adad --qmp "= $SOCKET" +$PYTHON ../../contrib/backup/qemu-backup.py drive add --id virtio0 --guest= adad --target "$TEST_DIR"/virtio0 +echo +echo "=3D=3D Creating backup =3D=3D" +$PYTHON ../../contrib/backup/qemu-backup.py backup --guest adad +_send_qemu_cmd $QEMU_HANDLE 'quit' '' +wait=3D1 _cleanup_qemu +echo +echo "=3D=3D Comparing images =3D=3D" +$QEMU_IMG compare "$TEST_DIR"/virtio0 "$TEST_IMG" +_cleanup + +_launch_qemu -drive if=3Dvirtio,id=3Dvirtio0,file=3D"$TEST_IMG" -qmp "$SOC= KET",server,nowait +$PYTHON ../../contrib/backup/qemu-backup.py guest add --guest adad --qmp "= $SOCKET" +$PYTHON ../../contrib/backup/qemu-backup.py drive add --id virtio0 --guest= adad --target "$TEST_DIR"/virtio0 +echo +echo "=3D=3D Writing Pattern =3D=3D" +_send_qemu_cmd $QEMU_HANDLE 'qemu-io virtio0 "write -P 0x22 0 1M"' "(qemu)= " | _filter_qemu_io +echo +echo "=3D=3D Creating backup =3D=3D" +$PYTHON ../../contrib/backup/qemu-backup.py backup --guest adad +_send_qemu_cmd $QEMU_HANDLE 'quit' '' +wait=3D1 _cleanup_qemu +echo +echo "=3D=3D Comparing images =3D=3D" +$QEMU_IMG compare "$TEST_DIR"/virtio0 "$TEST_IMG" +_cleanup +_cleanup_test_img + +echo "*** done" +status=3D0 \ No newline at end of file diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out new file mode 100644 index 0000000..c60d47a --- /dev/null +++ b/tests/qemu-iotests/191.out @@ -0,0 +1,35 @@ +QA output created by 191 +Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D134217728 + +Successfully Added Guest +Successfully Added Drive + +=3D=3D Creating backup =3D=3D +Backup Started +*virtio0 +Backup Complete +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) Formatting 'TEST_DIR/virtio0', fmt=3Dqcow2 size=3D134217728 cluster= _size=3D65536 lazy_refcounts=3Doff refcount_bits=3D16 +quit + +=3D=3D Comparing images =3D=3D +Images are identical. +Successfully Added Guest +Successfully Added Drive + +=3D=3D Writing Pattern =3D=3D +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qemu-io virtio0 "write -P 0x22 0 1M" + +=3D=3D Creating backup =3D=3D +Backup Started +*virtio0 +Backup Complete +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) Formatting 'TEST_DIR/virtio0', fmt=3Dqcow2 size=3D134217728 cluster= _size=3D65536 lazy_refcounts=3Doff refcount_bits=3D16 +quit + +=3D=3D Comparing images =3D=3D +Images are identical. +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index afbdc42..66fa231 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -186,4 +186,6 @@ 188 rw auto quick 189 rw auto 190 rw auto quick +191 rw auto 192 rw auto quick +193 rw auto --=20 2.7.4 From nobody Mon Feb 9 11:59:06 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15040219399381004.6787753104794; Tue, 29 Aug 2017 08:52:19 -0700 (PDT) Received: from localhost ([::1]:45617 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dmioL-0006rM-NW for importer@patchew.org; Tue, 29 Aug 2017 11:52:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53886) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dmimd-0005mE-4o for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dmimZ-0000E1-AK for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:31 -0400 Received: from research.iiit.ac.in ([196.12.53.8]:58856) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dmimY-0000Az-HH for qemu-devel@nongnu.org; Tue, 29 Aug 2017 11:50:27 -0400 Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id 66C3474200E; Tue, 29 Aug 2017 21:20:23 +0530 (IST) Received: from research.iiit.ac.in ([127.0.0.1]) by localhost (research.iiit.ac.in [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id DNqt0juLMhK8; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id C797C744E2A; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from research.iiit.ac.in ([127.0.0.1]) by localhost (research.iiit.ac.in [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id RgtsiCOAqVHw; Tue, 29 Aug 2017 21:20:20 +0530 (IST) Received: from ishani-Inspiron-5558.iiit.ac.in (unknown [10.2.20.52]) by research.iiit.ac.in (Postfix) with ESMTPSA id AB43274200E; Tue, 29 Aug 2017 21:20:20 +0530 (IST) DKIM-Filter: OpenDKIM Filter v2.9.2 research.iiit.ac.in C797C744E2A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=research.iiit.ac.in; s=4E8815E6-5B55-11E4-B758-8D4964374E96; t=1504021820; bh=t+nJxYvRlw61frSZEKYZcR3T3UIVh+s2Pfysadfr3sE=; h=From:To:Subject:Date:Message-Id; b=sP7c1fCsjP1diICYI7sguUbZDVetzYygp9CtZXxMI+r4aLMfQISs9OhJiVg9clKcY tYDLtMBF4vTtFGe02ot18KssRVFPdCckGOXIWLPZsjs/zuD1UKGbohgXOxxzutVLdS vW7i2wNI7b7ROzb//hE2UxLlwJuM2x6JmTk5r4+4= X-Virus-Scanned: amavisd-new at research.iiit.ac.in From: Ishani Chugh To: qemu-devel@nongnu.org Date: Tue, 29 Aug 2017 21:20:18 +0530 Message-Id: <1504021818-12128-4-git-send-email-chugh.ishani@research.iiit.ac.in> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1504021818-12128-1-git-send-email-chugh.ishani@research.iiit.ac.in> References: <1504021818-12128-1-git-send-email-chugh.ishani@research.iiit.ac.in> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 196.12.53.8 Subject: [Qemu-devel] [PATCH 3/3] Add manpage for QEMU Backup Tool X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ishani Chugh , jsnow@redhat.com, stefanha@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" qemu-backup will be a command-line tool for performing full and=20 incremental disk backups on running VMs. It is intended as a reference implementation for management stack and backup developers to see QEMU's backup features in action. The following commit is an initial implementation of manpage listing the commands which the=20 backup tool will support. The manpage wil be build along with other docs when configure is provided with --enable-docs flag in the=20 location contrib/backup in build directory. Signed-off-by: Ishani Chugh --- Makefile | 14 ++-- contrib/backup/qemu-backup.texi | 144 ++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 contrib/backup/qemu-backup.texi diff --git a/Makefile b/Makefile index 81447b1..ba1574d 100644 --- a/Makefile +++ b/Makefile @@ -209,6 +209,7 @@ ifdef BUILD_DOCS DOCS=3Dqemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 DOCS+=3Ddocs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/= interop/qemu-qmp-ref.7 DOCS+=3Ddocs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/in= terop/qemu-ga-ref.7 +DOCS+=3Dcontrib/backup/qemu-backup.html contrib/backup/qemu-backup.txt ifdef CONFIG_VIRTFS DOCS+=3Dfsdev/virtfs-proxy-helper.1 endif @@ -508,6 +509,8 @@ VERSION ?=3D $(shell cat VERSION) =20 dist: qemu-$(VERSION).tar.bz2 =20 +qemu-backup.8: contrib/backup/qemu-backup.texi + qemu-%.tar.bz2: $(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2= ,%,$@)" =20 @@ -719,16 +722,19 @@ fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helpe= r.texi qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi qemu-ga.8: qemu-ga.texi =20 -html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-re= f.html -info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-re= f.info -pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.p= df -txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.t= xt +html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-re= f.html contrib/backup/qemu-backup.html +info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-re= f.info contrib/backup/qemu-backup.info +pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.p= df contrib/backup/qemu-backup.pdf +txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.t= xt contrib/backup/qemu-backup.txt =20 qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \ qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \ qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \ qemu-monitor-info.texi =20 +contrib/backup/qemu-backup.html contrib/backup/qemu-backup.pdf contrib/bac= kup/qemu-backup.txt contrib/backup/qemu-backup.info: \ + contrib/backup/qemu-backup.texi + docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \ docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \ docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7: \ diff --git a/contrib/backup/qemu-backup.texi b/contrib/backup/qemu-backup.t= exi new file mode 100644 index 0000000..68e7231 --- /dev/null +++ b/contrib/backup/qemu-backup.texi @@ -0,0 +1,144 @@ +\input texinfo +@setfilename qemu-backup + +@documentlanguage en +@documentencoding UTF-8 + +@settitle QEMU Backup Tool +@copying + +Copyright @copyright{} 2017 The QEMU Project developers +@end copying +@ifinfo +@direntry +* QEMU: (QEMU-backup). Man page for QEMU Backup Tool. +@end direntry +@end ifinfo +@iftex +@titlepage +@sp 7 +@center @titlefont{QEMU Backup Tool} +@sp 1 +@sp 3 +@end titlepage +@end iftex +@ifnottex +@node Top +@top Short Sample + +@menu +* Name:: +* Synopsis:: +* List of Commands:: +* Command Parameters:: +* Command Descriptions:: +* License:: +@end menu + +@end ifnottex + +@node Name +@chapter Name + +QEMU disk backup tool. + +@node Synopsis +@chapter Synopsis + +qemu-backup command [command options]. + +@node List of Commands +@chapter List of Commands +@itemize +@item qemu-backup guest add --guest guestname --qmp socketpath +@item qemu-backup guest list +@item qemu-backup drive add --id driveid --guest guestname --target target +@item qemu-backup drive add --all --guest guestname --target target +@item qemu-backup drive list --guest guestname +@item qemu-backup backup [--inc] --guest guestname +@item qemu-backup restore --guest guestname +@item qemu-backup guest remove --guest guestname +@item qemu-backup drive remove --guest guestname --id driveid +@end itemize +@node Command Parameters +@chapter Command Parameters +@itemize +@item --all: Add all the drives present in a guest which are suitable for = backup. +@item --guest: Name of the guest. +@item --id: id of guest or drive. +@item --inc: (Optional) For incremental backup. +@item --qmp: Path of qmp socket. +@item --target: Destination path on which you want your backup to be made. +@end itemize + +@node Command Descriptions +@chapter Command Descriptions +@itemize +@item qemu-backup guest add --guest guestname --qmp socketpath +This command adds a guest to the configuration file given its path to qmp = socket. + +example: +qemu-backup guest add --id=3Dfedora --qmp=3Dunix:/var/run/qemu/fedora.sock + +qemu-backup guest add --id=3Dfedora --qmp=3Dtcp:localhost:4444 + +@item qemu-backup guest list +This commands lists the names of guests which are added to configuration f= ile. + +@item qemu-backup drive add --guest guestname --id driveid --target target +This command adds different drives for backup in a particular guest by giv= ing the name of drive to be backed up and target imagefile in which we want= to store the drive backup. + +example: qemu-backup drive add --guest=3Dfedora --id=3Droot --target=3D/ba= ckup/root.img + +@item qemu-backup drive add --all --guest guestname --destination destinat= ion +This command adds all the drives of the guest for backup other than CDROM = drive and read-only drives. Here all the backup drives will have the same n= ames as original drives and target will be the destination folder. + +example: qemu-backup drive add --all --guest fedora --destination =3D/back= up/fedora/ + +@item qemu-backup drive list --guest guestname +This commands gives the names of the drive present in a guest which are ad= ded for backup. + +example: qemu-backup drive list --guest=3Dfedora + +@item qemu-backup backup --guest guestname + +This command makes the backup of the drives, in their respective given des= tinations. The ids of drive and their destinations are taken from the confi= guration file. + +example: qemu-backup backup --guest=3Dfedora + +@item qemu-backup restore --guest guestname +This command is needed if we want to restore the backup. It will list the = commands to be run for performing the same but will not perform any action. + +example: qemu-backup restore --guest=3Dfedora + +@item qemu-backup guest remove --guest guestname +This command removes the guest from the configuration file. + +example: qemu-backup guest remove --guest=3Dfedora + +@item qemu-backup drive remove --guest guestname --id driveid +This command helps remove a drive which is set for backup in configuration= of given host. + +example: drive remove --guest=3Dfedora --id=3Droot + +@item A full backup can be performed by following the given steps: + +Perform a full backup of 'vm001', which has one drive: + +qemu-backup guest add --guest vm001 --qmp /path/to/vm001.sock + +qemu-backup add --id drive0 --guest vm001 --target /backups/vm001-drive0.i= mg + +qemu-backup backup --guest vm001 + + +@end itemize + +@node License +@appendix License +QEMU is a trademark of Fabrice Bellard. +QEMU is released under the +@url{https://www.gnu.org/licenses/gpl-2.0.txt,GNU General Public License}, +version 2. Parts of QEMU have specific licenses, see file +@url{http://git.qemu.org/?p=3Dqemu.git;a=3Dblob_plain;f=3DLICENSE,LICENSE}. +@bye --=20 2.7.4