Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM deviantony/python-dev

RUN apt-key adv --keyserver keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1C4CBDCDCD2EFD2A
RUN echo 'deb http://repo.percona.com/apt trusty main\ndeb-src http://repo.percona.com/apt trusty main'\
> /etc/apt/sources.list.d/percona.list

Expand Down
29 changes: 22 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,27 @@ You can also specify the following options:
* --log-file: Log file for the script (default: */var/log/mysql/pyxtrabackup.log*).
* --out-file: Log file for innobackupex output (default: */var/log/mysql/xtrabackup.out*).
* --backup-threads: You can specify more threads in order to backup quicker (default: 1).

* --no-compress: Do not compress the backup archive.

Restoration
-----------

The archive is containing a binary backup of a MySQL server, all you need to do in order to restore the backup is to extract the content of the archive in your MySQL datadir, setup the permissions for the files and start your server:
The archive is containing a binary backup of a MySQL server, all you need to do in order to restore the backup is to extract the content of the archive in your MySQL datadir, setup the permissions for the files and start your server.

::
Clean the MySQL datadir::

$ sudo rm -rf /path/to/mysql/datadir/*

If you compressed the archive, uncompress and extract it::

$ sudo tar xvpzf /path/to/backup_archive.tar.gz -C /path/to/mysql/datadir
$ sudo chown -R mysql:mysql /path/to/mysql/datadir

Otherwise you just need to extract it::

$ sudo tar xvpf /path/to/backup_archive.tar -C /path/to/mysql/datadir

Then restart your MySQL server::

$ sudo service mysql start

Setup an incremental backup cycle
Expand Down Expand Up @@ -91,21 +100,26 @@ You can also specify the following options:
* --log-file: Log file for the script (default: */var/log/mysql/pyxtrabackup-inc.log*).
* --out-file: Log file for innobackupex output (default: */var/log/mysql/xtrabackup.out*).
* --backup-threads: You can specify more threads in order to backup quicker (default: 1).
* --no-compress: Do not compress the backup archives.


Restoration
-----------

*WARNING*: The folder structure and the file names created by the *pyxtrabackup-inc* binary needs to be respected in order to restore successfully:

* TIMESTAMP_FOLDER/INC/base_backup_DATETIME.tar.gz
* TIMESTAMP_FOLDER/INC/inc_1_backup_DATETIME.tar.gz
* TIMESTAMP_FOLDER/INC/inc_N_backup_DATETIME.tar.gzz
* TIMESTAMP_FOLDER/INC/base_backup_DATETIME.tar(.gz)
* TIMESTAMP_FOLDER/INC/inc_1_backup_DATETIME.tar(.gz)
* TIMESTAMP_FOLDER/INC/inc_N_backup_DATETIME.tar(.gz)

To restore an incremental backup, you'll need to use the *pyxtrabackup-restore* binary the following way: ::

$ pyxtrabackup-restore --base-archive=<PATH TO BASE BACKUP> --incremental-archive=<PATH TO INCREMENTAL BACKUP> --user=<MYSQL USER>

Also, if you did use the *--no-compress* option with the backup tools, you'll need to specify the *--uncompressed-archives* option: ::

$ pyxtrabackup-restore --base-archive=<PATH TO BASE BACKUP> --incremental-archive=<PATH TO INCREMENTAL BACKUP> --user=<MYSQL USER> --uncompressed-archives

The binary will stop the MySQL service, remove all files present in MySQL datadir and import all the incremental backups up to the specified last incremental backup.

For example, using the following parameters: ::
Expand All @@ -125,6 +139,7 @@ You can also specify the following options:
* --log-file: Log file for the script (default: */var/log/mysql/pyxtrabackup-restore.log*).
* --out-file: Log file for innobackupex output (default: */var/log/mysql/xtrabackup.out*).
* --backup-threads: You can specify more threads in order to backup quicker (default: 1).
* --uncompressed-archives: Do not try to uncompress backup archives. Use this option if you used the backup tool with --no-compress.

Limitations
===========
Expand Down
27 changes: 16 additions & 11 deletions xtrabackup/backup_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

class BackupTool:

def __init__(self, log_file, output_file):
def __init__(self, log_file, output_file, no_compression):
self.log_manager = log_manager.LogManager()
self.stop_watch = timer.Timer()
self.setup_logging(log_file)
self.command_executor = CommandExecutor(output_file)
self.compress = not no_compression

def setup_logging(self, log_file):
self.logger = logging.getLogger(__name__)
Expand All @@ -31,7 +32,10 @@ def prepare_workdir(self, path):
filesystem_utils.mkdir_path(path, 0o755)
self.workdir = path + '/xtrabackup_tmp'
self.logger.debug("Temporary workdir: " + self.workdir)
self.archive_path = path + '/backup.tar.gz'
if self.compress:
self.archive_path = path + '/backup.tar.gz'
else:
self.archive_path = path + '/backup.tar'
self.logger.debug("Temporary archive: " + self.archive_path)

def prepare_repository(self, repository, incremental):
Expand All @@ -51,7 +55,7 @@ def prepare_archive_name(self, incremental, incremental_cycle):
else:
backup_prefix = ''
self.final_archive_path = filesystem_utils.prepare_archive_path(
self.backup_repository, backup_prefix)
self.backup_repository, backup_prefix, self.compress)

def exec_incremental_backup(self, user, password, thread_count):
self.stop_watch.start_timer()
Expand Down Expand Up @@ -104,18 +108,18 @@ def prepare_backup(self, redo_logs):
self.stop_watch.stop_timer(),
self.stop_watch.duration_in_seconds())

def compress_backup(self):
def archive_backup(self):
self.stop_watch.start_timer()
try:
self.command_executor.create_archive(
self.workdir, self.archive_path)
self.workdir, self.archive_path, self.compress)
except ProcessError:
self.logger.error(
'An error occured during the backup compression.',
'An error occured during the archiving of the backup.',
exc_info=True)
self.clean()
raise
self.logger.info("Backup compression time: %s - Duration: %s",
self.logger.info("Backup archiving time: %s - Duration: %s",
self.stop_watch.stop_timer(),
self.stop_watch.duration_in_seconds())

Expand All @@ -127,7 +131,7 @@ def transfer_backup(self, repository):
self.final_archive_path)
except Exception:
self.logger.error(
'An error occured during the backup compression.',
'An error occured during the backup transfer.',
exc_info=True)
self.clean()
raise
Expand Down Expand Up @@ -178,14 +182,15 @@ def load_incremental_data(self):
self.clean()
raise

def start_full_backup(self, repository, workdir, user, password, threads):
def start_full_backup(self, repository, workdir, user,
password, threads):
self.check_prerequisites(repository)
self.prepare_workdir(workdir)
self.prepare_repository(repository, False)
self.prepare_archive_name(False, False)
self.exec_full_backup(user, password, threads)
self.prepare_backup(False)
self.compress_backup()
self.archive_backup()
self.transfer_backup(repository)
self.clean()

Expand All @@ -202,6 +207,6 @@ def start_incremental_backup(self, repository, incremental,
self.prepare_archive_name(incremental, True)
self.exec_full_backup(user, password, threads)
self.save_incremental_data(incremental)
self.compress_backup()
self.archive_backup()
self.transfer_backup(repository)
self.clean()
16 changes: 12 additions & 4 deletions xtrabackup/command_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,27 @@ def exec_chown(self, user, group, directory_path):
command = ['/bin/chown', '-R', user + ':' + group, directory_path]
self.exec_command(command)

def create_archive(self, directory, archive_path):
def create_archive(self, directory, archive_path, compress):
if compress:
tar_options = 'cpvzf'
else:
tar_options = 'cpvf'
command = [
'tar',
'cpvzf',
tar_options,
archive_path,
'-C',
directory, '.']
self.exec_command(command)

def extract_archive(self, archive_path, destination_path):
def extract_archive(self, archive_path, destination_path, compressed):
if compressed:
tar_options = 'xpvzf'
else:
tar_options = 'xpvf'
command = [
'tar',
'xpvzf',
tar_options,
archive_path,
'-C',
destination_path]
Expand Down
9 changes: 6 additions & 3 deletions xtrabackup/filesystem_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ def create_sub_repository(repository_path, sub_directory):
return sub_repository


def prepare_archive_path(archive_sub_repository, prefix):
def prepare_archive_path(archive_sub_repository, prefix, compress):
archive_path = ''.join([
archive_sub_repository,
'/',
prefix,
'backup_',
datetime.datetime.now().strftime("%Y%m%d_%H%M"),
'.tar.gz'])
datetime.datetime.now().strftime("%Y%m%d_%H%M")])
if compress:
archive_path = archive_path + '.tar.gz'
else:
archive_path = archive_path + '.tar'
return archive_path


Expand Down
37 changes: 27 additions & 10 deletions xtrabackup/full_backup.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
"""Xtrabackup script

Usage:
pyxtrabackup <repository> --user=<user> [--password=<pwd>] [--tmp-dir=<tmp>] [--log-file=<log>] [--out-file=<log>] [--backup-threads=<threads>]
pyxtrabackup <repository> --user=<user> \
[--password=<pwd>] \
[--tmp-dir=<tmp>] \
[--log-file=<log>] \
[--out-file=<log>] \
[--backup-threads=<threads>] \
[--no-compress]
pyxtrabackup (-h | --help)
pyxtrabackup --version


Options:
-h --help Show this screen.
--version Show version.
--user=<user> MySQL user.
--password=<pwd> MySQL password.
--tmp-dir=<tmp> Temporary directory [default: /tmp].
--log-file=<log> Log file [default: /var/log/mysql/pyxtrabackup.log].
--out-file=<log> Output file [default: /var/log/mysql/xtrabackup.out].
--backup-threads=<threads> Threads count [default: 1].
-h --help \
Show this screen.
--version \
Show version.
--user=<user> \
MySQL user.
--password=<pwd> \
MySQL password.
--tmp-dir=<tmp> \
Temporary directory [default: /tmp].
--log-file=<log> \
Log file [default: /var/log/mysql/pyxtrabackup.log].
--out-file=<log> \
Output file [default: /var/log/mysql/xtrabackup.out].
--backup-threads=<threads> \
Threads count [default: 1].
--no-compress \
Do not create a compressed archive of the backup.

"""
from docopt import docopt
Expand All @@ -25,7 +41,8 @@

def main():
arguments = docopt(__doc__, version='3.0.1')
backup_tool = BackupTool(arguments['--log-file'], arguments['--out-file'])
backup_tool = BackupTool(arguments['--log-file'], arguments['--out-file'],
arguments['--no-compress'])
try:
backup_tool.start_full_backup(arguments['<repository>'],
arguments['--tmp-dir'],
Expand Down
41 changes: 30 additions & 11 deletions xtrabackup/incremental_backup.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
"""Xtrabackup script

Usage:
pyxtrabackup-inc <repository> --user=<user> [--password=<pwd>] [--incremental] [--tmp-dir=<tmp>] [--log-file=<log>] [--out-file=<log>] [--backup-threads=<threads>]
pyxtrabackup-inc <repository> --user=<user> \
[--password=<pwd>] \
[--incremental] \
[--tmp-dir=<tmp>] \
[--log-file=<log>] \
[--out-file=<log>] \
[--backup-threads=<threads>] \
[--no-compress]
pyxtrabackup-inc (-h | --help)
pyxtrabackup --version


Options:
-h --help Show this screen.
--version Show version.
--user=<user> MySQL user.
--password=<pwd> MySQL password.
--incremental Start an incremental cycle.
--tmp-dir=<tmp> Temporary directory [default: /tmp].
--log-file=<log> Log file [default: /var/log/mysql/pyxtrabackup.log].
--out-file=<log> Output file [default: /var/log/mysql/xtrabackup.out].
--backup-threads=<threads> Threads count [default: 1].
-h --help \
Show this screen.
--version \
Show version.
--user=<user> \
MySQL user.
--password=<pwd> \
MySQL password.
--incremental \
Start an incremental cycle.
--tmp-dir=<tmp> \
Temporary directory [default: /tmp].
--log-file=<log> \
Log file [default: /var/log/mysql/pyxtrabackup.log].
--out-file=<log> \
Output file [default: /var/log/mysql/xtrabackup.out].
--backup-threads=<threads> \
Threads count [default: 1].
--no-compress \
Do not create a compressed archive of the backup.

"""
from docopt import docopt
Expand All @@ -26,7 +44,8 @@

def main():
arguments = docopt(__doc__, version='3.0.1')
backup_tool = BackupTool(arguments['--log-file'], arguments['--out-file'])
backup_tool = BackupTool(arguments['--log-file'], arguments['--out-file'],
arguments['--no-compress'])
try:
backup_tool.start_incremental_backup(arguments['<repository>'],
arguments['--incremental'],
Expand Down
Loading