From nobody Fri Apr 19 00:21:00 2024 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 1502387174234103.16230966586681; Thu, 10 Aug 2017 10:46:14 -0700 (PDT) Received: from localhost ([::1]:54470 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dfrXA-0005M2-Q7 for importer@patchew.org; Thu, 10 Aug 2017 13:46:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53557) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dfrVv-0004gz-Ml for qemu-devel@nongnu.org; Thu, 10 Aug 2017 13:44:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dfrVr-0002UK-PQ for qemu-devel@nongnu.org; Thu, 10 Aug 2017 13:44:55 -0400 Received: from research.iiit.ac.in ([196.12.53.8]:49124) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dfrVq-0002OM-Ud for qemu-devel@nongnu.org; Thu, 10 Aug 2017 13:44:51 -0400 Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id 463C3741D01; Thu, 10 Aug 2017 23:14:47 +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 1Oxug0p1T0o9; Thu, 10 Aug 2017 23:14:43 +0530 (IST) Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id 9DFF8741F36; Thu, 10 Aug 2017 23:14:43 +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 Byk6CNxM1txe; Thu, 10 Aug 2017 23:14:43 +0530 (IST) Received: from ishani-Inspiron-5558.iiit.ac.in (unknown [10.2.132.220]) by research.iiit.ac.in (Postfix) with ESMTPSA id 38CF7741D01; Thu, 10 Aug 2017 23:14:43 +0530 (IST) DKIM-Filter: OpenDKIM Filter v2.9.2 research.iiit.ac.in 9DFF8741F36 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=research.iiit.ac.in; s=4E8815E6-5B55-11E4-B758-8D4964374E96; t=1502387083; bh=SwQh8I+DBgUMOAqm5u4dnKoIiEWQ4SIhQFqziYkjn4s=; h=From:To:Subject:Date:Message-Id; b=OvFoZnjs6/1El8AVJ/abs9NCDrgbMTu+7l8lXL/w3L7mYn/kyjj23Jf89S4KY7lyx kPHIQ11iRv0mHncHrjZdBBjLhrusDTgluFd12Xxxp+bKZTOHIfYYAqoyqXQfqtsVGB QRpYLYRDz0iJyTBmhPTA9V3mXbuBMgdEhDc7rvHA= X-Virus-Scanned: amavisd-new at research.iiit.ac.in From: Ishani Chugh To: qemu-devel@nongnu.org Date: Thu, 10 Aug 2017 23:14:34 +0530 Message-Id: <1502387075-29078-2-git-send-email-chugh.ishani@research.iiit.ac.in> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1502387075-29078-1-git-send-email-chugh.ishani@research.iiit.ac.in> References: <1502387075-29078-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/2] 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 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 backup tool will support. The manpage wil be build along with other docs when configure is provided with --enable-docs flag in the location contrib/backup in build directory. Signed-off-by: Ishani Chugh --- Makefile | 15 +++-- contrib/backup/qemu-backup.texi | 135 ++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 contrib/backup/qemu-backup.texi diff --git a/Makefile b/Makefile index 16a0430..1826a74 100644 --- a/Makefile +++ b/Makefile @@ -209,6 +209,8 @@ 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 +DOCS+=3Dcontrib/backup/qemu-backup.pdf contrib/backup/qemu-backup.info ifdef CONFIG_VIRTFS DOCS+=3Dfsdev/virtfs-proxy-helper.1 endif @@ -508,6 +510,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 +723,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..ba9f9ec --- /dev/null +++ b/contrib/backup/qemu-backup.texi @@ -0,0 +1,135 @@ +\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 [--tcp] +@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. +@item --tcp: (Optional) Specifies TCP socket. +@end itemize + +@node Command Descriptions +@chapter Command Descriptions +@itemize +@item qemu-backup guest add --guest guestname --qmp socketpath [--tcp] +This command adds a guest to the configuration file given its path to qmp = socket. + +example: +qemu-backup guest add --id=3Dfedora --qmp=3D/var/run/qemu/fedora.sock + +qemu-backup guest add --id=3Dfedora --qmp=3Dlocalhost:4444 --tcp + +@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 + + +@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 From nobody Fri Apr 19 00:21:00 2024 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 1502387275593342.36028869665756; Thu, 10 Aug 2017 10:47:55 -0700 (PDT) Received: from localhost ([::1]:54479 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dfrYo-0006LR-CW for importer@patchew.org; Thu, 10 Aug 2017 13:47:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53561) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dfrVv-0004h1-PS for qemu-devel@nongnu.org; Thu, 10 Aug 2017 13:44:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dfrVr-0002UN-PX for qemu-devel@nongnu.org; Thu, 10 Aug 2017 13:44:55 -0400 Received: from research.iiit.ac.in ([196.12.53.8]:49112) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dfrVq-0002No-Er for qemu-devel@nongnu.org; Thu, 10 Aug 2017 13:44:51 -0400 Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id 02602741D66; Thu, 10 Aug 2017 23:14:47 +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 GiR7BR8fYAbR; Thu, 10 Aug 2017 23:14:44 +0530 (IST) Received: from localhost (localhost [127.0.0.1]) by research.iiit.ac.in (Postfix) with ESMTP id 411B7741D01; Thu, 10 Aug 2017 23:14:44 +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 JXSc_1dGi4SX; Thu, 10 Aug 2017 23:14:44 +0530 (IST) Received: from ishani-Inspiron-5558.iiit.ac.in (unknown [10.2.132.220]) by research.iiit.ac.in (Postfix) with ESMTPSA id 8FEB6741CC7; Thu, 10 Aug 2017 23:14:43 +0530 (IST) DKIM-Filter: OpenDKIM Filter v2.9.2 research.iiit.ac.in 411B7741D01 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=research.iiit.ac.in; s=4E8815E6-5B55-11E4-B758-8D4964374E96; t=1502387084; bh=s/RdajygMVHfgrKeiHv5R2sQfJUBzm0ljSafceUpYSY=; h=From:To:Subject:Date:Message-Id; b=L0icRhCRJPM4+pNhfYqsHaKVhvI/cBm3SbKZ0i6IRNgOjJPYkOzy2FPrWntHflzUp k/1OCFKfUFmSTrPAcPUd6VX7b/ykuwBE87FgFpZFjHoSpQHuTJa1uo3hqv52lzF4RM k3Gj6YFGuD6U+6w6AUdGQEKm6Wl6jf1Tci1lIviI= X-Virus-Scanned: amavisd-new at research.iiit.ac.in From: Ishani Chugh To: qemu-devel@nongnu.org Date: Thu, 10 Aug 2017 23:14:35 +0530 Message-Id: <1502387075-29078-3-git-send-email-chugh.ishani@research.iiit.ac.in> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1502387075-29078-1-git-send-email-chugh.ishani@research.iiit.ac.in> References: <1502387075-29078-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/2] 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 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 | 309 ++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 309 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..9bbbdb7 --- /dev/null +++ b/contrib/backup/qemu-backup.py @@ -0,0 +1,309 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013 Red Hat, Inc. +# +# 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('~')+'/.qemu/backup/conf= ig'): + 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.expanduser('~')+'/.qemu/backu= p'): + os.makedirs(os.path.expanduser('~')+'/.qemu/backup') + except: + print("Cannot find the config file", file=3Dsys.stderr) + 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) + 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": []}} + for key in self.config[guest_name]: + if key.startswith("drive_"): + drive =3D key[len('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) + connection.cmd_obj(cmd) + if connection.pull_event(wait=3DTrue)['event'] =3D=3D 'BLOCK_JOB_C= OMPLETED': + print("Backup Complete") + else: + print("Cannot complete backup", file=3Dsys.stderr) + + 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 guest_name not in self.config.sections(): + print ("Cannot find specified guest", file=3Dsys.stderr) + exit(1) + + if "drive_"+drive_id in self.config[guest_name]: + print ("Drive already marked for backup", file=3Dsys.stderr) + 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) + 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) + 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, replace:") + 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(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