Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added mediarestore command #178

Merged
merged 7 commits into from
Jul 31, 2016
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 70 additions & 1 deletion dbbackup/management/commands/_base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
"""
Abstract Command.
"""
import sys
from logging import getLogger
from optparse import make_option
from django.core.management.base import BaseCommand, LabelCommand
from shutil import copyfileobj

from django.core.management.base import BaseCommand, LabelCommand, CommandError
from django.utils import six

from ...storage.base import StorageError

input = raw_input if six.PY2 else input # @ReservedAssignment


class BaseDbBackupCommand(LabelCommand):
Expand All @@ -24,3 +32,64 @@ class BaseDbBackupCommand(LabelCommand):
def _set_logger_level(self):
level = 60 if self.quiet else (self.verbosity + 1) * 10
self.logger.setLevel(level)

def _ask_confirmation(self):
answer = input("Are you sure you want to continue? [Y/n] ")
if answer.lower().startswith('n'):
self.logger.info("Quitting")
sys.exit(0)

def read_from_storage(self, path):
return self.storage.read_file(path)

def write_to_storage(self, file, path):
self.logger.info("Writing file to %s: %s, filename: %s",
self.storage.name, self.storage.backup_dir,
path)
self.storage.write_file(file, path)

def read_local_file(self, path):
"""Open file in read mode on local filesystem."""
return open(path, 'rb')

def write_local_file(self, outputfile, path):
"""Write file to the desired path."""
self.logger.info("Writing file to %s", path)
outputfile.seek(0)
with open(path, 'wb') as fd:
copyfileobj(outputfile, fd)

def _get_backup_file(self):
if self.path:
input_filename = self.path
input_file = self.read_local_file(self.path)
else:
if self.filename:
input_filename = self.filename
# Fetch the latest backup if filepath not specified
else:
self.logger.info("Finding latest backup")
# database = self.database['NAME'] if self.content_type == 'db' else None
try:
input_filename = self.storage.get_latest_backup(
encrypted=self.decrypt,
compressed=self.uncompress,
content_type=self.content_type)
# TODO: Make better filter
# database=database)
except StorageError as err:
raise CommandError(err.args[0])
input_file = self.read_from_storage(input_filename)
return input_filename, input_file

def _cleanup_old_backups(self):
"""
Cleanup old backups, keeping the number of backups specified by
DBBACKUP_CLEANUP_KEEP and any backups that occur on first of the month.
"""
# database = self.database if self.content_type == 'db' else None
file_list = self.storage.clean_old_backups(encrypted=self.encrypt,
compressed=self.compress,
content_type=self.content_type)
# TODO: Make better filter
# database=database)
29 changes: 7 additions & 22 deletions dbbackup/management/commands/dbbackup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
print_function, unicode_literals)

from optparse import make_option
from shutil import copyfileobj

from django.core.management.base import CommandError

Expand All @@ -16,9 +15,10 @@


class Command(BaseDbBackupCommand):
help = """
Backup a database, encrypt and/or compress and write to storage.
"""
help = """Backup a database, encrypt and/or compress and write to
storage."""
content_type = 'db'

option_list = BaseDbBackupCommand.option_list + (
make_option("-c", "--clean", dest='clean', action="store_true",
default=False, help="Clean up old backup files"),
Expand All @@ -42,7 +42,6 @@ def handle(self, **options):
self.verbosity = int(options.get('verbosity'))
self.quiet = options.get('quiet')
self.clean = options.get('clean')
self.clean_keep = dbbackup_settings.CLEANUP_KEEP
self.database = options.get('database')
self.servername = options.get('servername')
self.compress = options.get('compress')
Expand All @@ -57,10 +56,7 @@ def handle(self, **options):
try:
self._save_new_backup(database)
if self.clean:
self.storage.clean_old_backups(self.encrypt,
self.compress,
content_type='db',
database=self.database)
self._cleanup_old_backups()
except StorageError as err:
raise CommandError(err)

Expand All @@ -80,20 +76,9 @@ def _save_new_backup(self, database):
outputfile = encrypted_file
filename = self.filename if self.filename else filename
if not self.quiet:
self.logger.info("Backup tempfile created: %s", utils.handle_size(outputfile))
self.logger.info("Backup size: %s", utils.handle_size(outputfile))
# Store backup
if self.path is None:
self.logger.info("Writing file to %s: %s, filename: %s",
self.storage.name, self.storage.backup_dir,
filename)
self.storage.write_file(outputfile, filename)
self.write_to_storage(outputfile, filename)
else:
self.logger.info("Writing file to %s", self.path)
self.write_local_file(outputfile, self.path)

# TODO: Define chunk size
def write_local_file(self, outputfile, path):
"""Write file to the desired path."""
outputfile.seek(0)
with open(path, 'wb') as fd:
copyfileobj(outputfile, fd)
57 changes: 10 additions & 47 deletions dbbackup/management/commands/dbrestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,32 @@
from __future__ import (absolute_import, division,
print_function, unicode_literals)

import os
import sys
import warnings
from optparse import make_option

from django.conf import settings
from django.core.management.base import CommandError
from django.utils import six
from django.db import connection

from ._base import BaseDbBackupCommand
from ... import utils
from ...db.base import get_connector
from ...storage.base import BaseStorage, StorageError

input = raw_input if six.PY2 else input # @ReservedAssignment


class Command(BaseDbBackupCommand):
help = """
Restore a backup from storage, encrypted and/or compressed.
"""
help = """Restore a database backup from storage, encrypted and/or
compressed."""
content_type = 'db'

option_list = BaseDbBackupCommand.option_list + (
make_option("-d", "--database", help="Database to restore"),
make_option("-i", "--input-filename", help="Specify filename to backup from"),
make_option("-I", "--input-path", help="Specify path on local filesystem to backup from"),
make_option("-s", "--servername", help="Use a different servername backup"),
make_option("-l", "--list", action='store_true', default=False, help="List backups in the backup directory"),

make_option("-c", "--decrypt", help="Decrypt data before restoring", default=False, action='store_true'),
make_option("-p", "--passphrase", help="Passphrase for decrypt file", default=None),
make_option("-z", "--uncompress", help="Uncompress gzip data before restoring", action='store_true'),
make_option("-z", "--uncompress", help="Uncompress gzip data before restoring", action='store_true', default=False),
)

def handle(self, *args, **options):
Expand All @@ -54,8 +48,6 @@ def handle(self, *args, **options):
self.interactive = options.get('interactive')
self.database = self._get_database(options)
self.storage = BaseStorage.storage_factory()
if options.get('list'):
return self._list_backups()
self._restore_backup()
except StorageError as err:
raise CommandError(err)
Expand All @@ -74,23 +66,10 @@ def _get_database(self, options):
def _restore_backup(self):
"""Restore the specified database."""
self.logger.info("Restoring backup for database: %s", self.database['NAME'])
if self.path:
input_filename = self.path
input_file = self.read_local_file(self.path)
else:
if self.filename:
input_filename = self.filename
# Fetch the latest backup if filepath not specified
else:
self.logger.info("Finding latest backup")
try:
input_filename = self.storage.get_latest_backup(encrypted=self.decrypt,
compressed=self.uncompress)
except StorageError as err:
raise CommandError(err.args[0])
input_file = self.storage.read_file(input_filename)

input_filename, input_file = self._get_backup_file()
self.logger.info("Restoring: %s" % input_filename)

if self.decrypt:
unencrypted_file, input_filename = utils.unencrypt_file(input_file, input_filename,
self.passphrase)
Expand All @@ -100,26 +79,10 @@ def _restore_backup(self):
uncompressed_file, input_filename = utils.uncompress_file(input_file, input_filename)
input_file.close()
input_file = uncompressed_file

self.logger.info("Restore tempfile created: %s", utils.handle_size(input_file))
if self.interactive:
answer = input("Are you sure you want to continue? [Y/n]")
if answer.lower().startswith('n'):
self.logger.info("Quitting")
sys.exit(0)
self._ask_confirmation()

input_file.seek(0)
self.connector.restore_dump(input_file)

# TODO: Remove this
def _list_backups(self):
"""List backups in the backup directory."""
msg = "'dbbrestore --list' is deprecated, use 'listbackup'."
warnings.warn(msg, DeprecationWarning)
self.logger.info("Listing backups on %s in /%s:", self.storage.name, self.storage.backup_dir)
for filepath in self.storage.list_directory():
self.logger.info(" %s", os.path.basename(filepath))
# TODO: Implement filename_details method
# print(utils.filename_details(filepath))

def read_local_file(self, path):
"""Open file on local filesystem."""
return open(path, 'rb')