[Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool

2017-08-29 Thread Ishani Chugh
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  [--target 
]

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 000..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=os.path.expanduser('~') +
+ '/.config/qemu/qemu-backup-config'):
+if "QEMU_BACKUP_CONFIG" in os.environ:
+self.config_file = os.environ["QEMU_BACKUP_CONFIG"]
+else:
+self.config_file = 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=sys.stderr)
+sys.exit(1)
+self.config = configparser.ConfigParser()
+self.config.read(self.config_file)
+
+def write_config(self):
+"""
+Writes configuration to ini file.
+"""
+config_file = 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=sys.stderr)
+sys.exit(1)
+
+self.verify_guest_running(guest_name)
+connection = QEMUMonitorProtocol(
+ self.get_socket_address(
+ self.config[guest_name]['qmp']))
+connection.connect()
+cmd = {"execute": "transaction", "arguments": {"actions": []}}
+drive_list = []
+for key in self.config[guest_name]:
+if key.startswith("drive_"):
+drive = key[len('drive_'):]
+drive_list.append(drive)
+target = self.config[guest_name][key]
+sub_cmd = {"type": "drive-backup", "data": {"device": drive,
+"target": target,
+"sync": "full"}

[Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool

2017-08-29 Thread Ishani Chugh
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  [--target 
]

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 | 339 ++
 1 file changed, 339 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 000..8c17486
--- /dev/null
+++ b/contrib/backup/qemu-backup.py
@@ -0,0 +1,339 @@
+#!/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=os.path.expanduser('~') +
+ '/.config/qemu/qemu-backup-config'):
+if "QEMU_BACKUP_CONFIG" in os.environ:
+self.config_file = os.environ["QEMU_BACKUP_CONFIG"]
+else:
+self.config_file = 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=sys.stderr)
+sys.exit(1)
+self.config = configparser.ConfigParser()
+self.config.read(self.config_file)
+
+def write_config(self):
+"""
+Writes configuration to ini file.
+"""
+config_file = 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=sys.stderr)
+sys.exit(1)
+
+self.verify_guest_running(guest_name)
+connection = QEMUMonitorProtocol(
+ self.get_socket_address(
+ self.config[guest_name]['qmp']))
+connection.connect()
+cmd = {"execute": "transaction", "arguments": {"actions": []}}
+drive_list = []
+for key in self.config[guest_name]:
+if key.startswith("drive_"):
+drive = key[len('drive_'):]
+drive_list.append(drive)
+target = self.config[guest_name][key]
+sub_cmd = {"type": "drive-backup", "data": {"device": drive,
+"target": target,
+"sync": "full"}}

Re: [Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool

2017-08-25 Thread Stefan Hajnoczi
On Wed, Aug 23, 2017 at 06:34:38PM +0530, Ishani Chugh wrote:
> +def write_config(self):
> +"""
> +Writes configuration to ini file.
> +"""
> +config_file = open(self.config_file+".tmp", 'w')

Please use whitespace around arithmetic operators:

  self.config_file + ".tmp"

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

self.config_file + ".tmp"

> +
> +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=sys.stderr)
> +sys.exit(1)
> +
> +self.verify_guest_running(guest_name)
> +connection = QEMUMonitorProtocol(
> + self.get_socket_address(
> + self.config[guest_name]['qmp']))
> +connection.connect()
> +cmd = {"execute": "transaction", "arguments": {"actions": []}}
> +drive_list = []
> +for key in self.config[guest_name]:
> +if key.startswith("drive_"):
> +drive = key[len('drive_'):]
> +drive_list.append(drive)
> +target = self.config[guest_name][key]
> +sub_cmd = {"type": "drive-backup", "data": {"device": drive,
> +"target": target,
> +"sync": "full"}}
> +cmd['arguments']['actions'].append(sub_cmd)
> +qmp_return = connection.cmd_obj(cmd)
> +if 'error' in qmp_return:
> +print(qmp_return['error']['desc'], file=sys.stderr)
> +sys.exit(1)
> +print("Backup Started")
> +while len(drive_list) != 0:

PEP8 says:

  For sequences, (strings, lists, tuples), use the fact that empty sequences 
are false.

  Yes: if not seq:
   if seq:

  No: if len(seq):
  if not len(seq):

This statement should be:

  while drive_list:

> +event = connection.pull_event(wait=True)
> +print(event)

Please remove debugging or add a --verbose command-line option that
makes the print statement conditional:

  if verbose:
  print(event)

> +if event['event'] == 'SHUTDOWN':
> +print("The guest was SHUT DOWN", file=sys.stderr)
> +sys.exit(1)
> +
> +if event['event'] == 'RESET':
> +print("The guest was Rebooted", file=sys.stderr)
> +sys.exit(1)

I think you found this is a soft reset and the blockjob is still
running.  There is no need to exit.  You can ignore this event.

> +
> +if event['event'] == 'BLOCK_JOB_COMPLETED':
> +if event['data']['device'] in drive_list and \
> +event['data']['type'] == 'backup':
> +print("*"+event['data']['device'])

Please use whitespace around arithmetic operators:

  print("*" + event['data']['device'])

> +drive_list.remove(event['data']['device'])
> +
> +if event['event'] == 'BLOCK_JOB_ERROR':
> +if event['data']['device'] in drive_list and \
> +event['data']['type'] == 'backup':
> +print(event['data']['device']+" Backup Failed", 
> file=sys.stderr)

The drive was not removed from drive_list so the loop never terminates.

sys.exit(1)?



[Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool

2017-08-23 Thread Ishani Chugh
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  [--target 
]

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 | 338 ++
 1 file changed, 338 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 000..b4a9efd
--- /dev/null
+++ b/contrib/backup/qemu-backup.py
@@ -0,0 +1,338 @@
+#!/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=os.path.expanduser('~') +
+ '/.config/qemu/qemu-backup-config'):
+if "QEMU_BACKUP_CONFIG" in os.environ:
+self.config_file = os.environ["QEMU_BACKUP_CONFIG"]
+else:
+self.config_file = 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=sys.stderr)
+sys.exit(1)
+self.config = configparser.ConfigParser()
+self.config.read(self.config_file)
+
+def write_config(self):
+"""
+Writes configuration to ini file.
+"""
+config_file = 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=sys.stderr)
+sys.exit(1)
+
+self.verify_guest_running(guest_name)
+connection = QEMUMonitorProtocol(
+ self.get_socket_address(
+ self.config[guest_name]['qmp']))
+connection.connect()
+cmd = {"execute": "transaction", "arguments": {"actions": []}}
+drive_list = []
+for key in self.config[guest_name]:
+if key.startswith("drive_"):
+drive = key[len('drive_'):]
+drive_list.append(drive)
+target = self.config[guest_name][key]
+sub_cmd = {"type": "drive-backup", "data": {"device": drive,
+"target": target,
+"sync": "full"}}
+   

Re: [Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool

2017-08-22 Thread Ishani


- On Aug 22, 2017, at 7:43 PM, stefanha stefa...@redhat.com wrote:

> On Mon, Aug 21, 2017 at 04:40:37PM +0530, Ishani Chugh wrote:
>> 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  
>> [--target
>> ]
>> 
>> 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 | 334 
>> ++
>>  1 file changed, 334 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 000..08570f7
>> --- /dev/null
>> +++ b/contrib/backup/qemu-backup.py
>> @@ -0,0 +1,334 @@
>> +#!/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=os.path.expanduser('~') +
>> + '/.config/qemu/qemu-backup-config'):
>> +if "QEMU_BACKUP_CONFIG" in os.environ:
>> +self.config_file = os.environ["QEMU_BACKUP_CONFIG"]
>> +else:
>> +self.config_file = 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=sys.stderr)
>> +sys.exit(1)
>> +self.config = configparser.ConfigParser()
>> +self.config.read(self.config_file)
>> +
>> +def write_config(self):
>> +"""
>> +Writes configuration to ini file.
>> +"""
>> +config_file = 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=sys.stderr)
>> +sys.exit(1)
>> +
>> +self.verify_guest_running(guest_name)
>> +connection = QEMUMonitorProtocol(
>> + self.get_socket_address(
>> + 
>> self.config[guest_name]['qmp']))
>> +connection.connect()
>> +cmd = {"execute": "transac

Re: [Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool

2017-08-22 Thread Stefan Hajnoczi
On Mon, Aug 21, 2017 at 04:40:37PM +0530, Ishani Chugh wrote:
> 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  
> [--target ]
> 
> 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 | 334 
> ++
>  1 file changed, 334 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 000..08570f7
> --- /dev/null
> +++ b/contrib/backup/qemu-backup.py
> @@ -0,0 +1,334 @@
> +#!/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=os.path.expanduser('~') +
> + '/.config/qemu/qemu-backup-config'):
> +if "QEMU_BACKUP_CONFIG" in os.environ:
> +self.config_file = os.environ["QEMU_BACKUP_CONFIG"]
> +else:
> +self.config_file = 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=sys.stderr)
> +sys.exit(1)
> +self.config = configparser.ConfigParser()
> +self.config.read(self.config_file)
> +
> +def write_config(self):
> +"""
> +Writes configuration to ini file.
> +"""
> +config_file = 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=sys.stderr)
> +sys.exit(1)
> +
> +self.verify_guest_running(guest_name)
> +connection = QEMUMonitorProtocol(
> + self.get_socket_address(
> + self.config[guest_name]['qmp']))
> +connection.connect()
> +cmd = {"execute": "transaction", "arguments": {"actions": []}}
> +drive_list = []
> +for key in self.config[guest_name]:
> +if key.startswith("drive_"):
> +drive = key[len('drive_'):]
> +  

[Qemu-devel] [PATCH 1/3] backup: QEMU Backup Tool

2017-08-21 Thread Ishani Chugh
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  [--target 
]

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 | 334 ++
 1 file changed, 334 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 000..08570f7
--- /dev/null
+++ b/contrib/backup/qemu-backup.py
@@ -0,0 +1,334 @@
+#!/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=os.path.expanduser('~') +
+ '/.config/qemu/qemu-backup-config'):
+if "QEMU_BACKUP_CONFIG" in os.environ:
+self.config_file = os.environ["QEMU_BACKUP_CONFIG"]
+else:
+self.config_file = 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=sys.stderr)
+sys.exit(1)
+self.config = configparser.ConfigParser()
+self.config.read(self.config_file)
+
+def write_config(self):
+"""
+Writes configuration to ini file.
+"""
+config_file = 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=sys.stderr)
+sys.exit(1)
+
+self.verify_guest_running(guest_name)
+connection = QEMUMonitorProtocol(
+ self.get_socket_address(
+ self.config[guest_name]['qmp']))
+connection.connect()
+cmd = {"execute": "transaction", "arguments": {"actions": []}}
+drive_list = []
+for key in self.config[guest_name]:
+if key.startswith("drive_"):
+drive = key[len('drive_'):]
+drive_list.append(drive)
+target = self.config[guest_name][key]
+sub_cmd = {"type": "drive-backup", "data": {"device": drive,
+"target": target,
+"sync": "full"}}
+