Add backup job list, create, edit, test views

This commit is contained in:
Roberto Rosario
2012-08-11 08:40:47 -04:00
parent 141db9dc34
commit 0e9cda6547
14 changed files with 506 additions and 26 deletions

View File

@@ -1,9 +1,47 @@
import logging
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.core.files.base import ContentFile
from django.core.management.commands.dumpdata import Command
from django.db import router, DEFAULT_DB_ALIAS
logger = logging.getLogger(__name__)
# Data types
class ElementDataBase(object):
"""
The basic unit of a backup, a data type
it is produced or consumed by the ElementBackup classes
"""
def save(self):
"""
Must return a file like object
"""
raise NotImplemented
def load(self, file_object):
"""
Must read a file like object and store content
"""
raise NotImplemented
class Fixture(ElementDataBase):
name = 'fixture'
def __init__(self, model_backup, content):
self.model_backup = model_backup
self.content = content
def save(self):
return ContentFile(name='%s_%s' % (self.__class__.__name__, self.model_backup.app_backup.name), content=self.content)
#def load(self):
# Element backup
class ElementBackupBase(object):
"""
Sub classes must provide at least:
@@ -28,7 +66,7 @@ class ElementBackupBase(object):
return unicode(self.__class__.label)
class ElementBackupModel(ElementBackupBase):
class ModelBackup(ElementBackupBase):
label = _(u'Model fixtures')
def __init__(self, models=None):
@@ -39,18 +77,23 @@ class ElementBackupModel(ElementBackupBase):
def backup(self):
"""
TODO: turn into a generator maybe?
"""
#TODO: turn into a generator
command = Command()
if not self.model_list:
result = [self.app_backup.name]
else:
result = [u'%s.%s' (self.app_backup.name, model) for model in self.model_list]
result = command.handle(u' '.join(result), format='json', indent=4, using=DEFAULT_DB_ALIAS, exclude=[], user_base_manager=False, use_natural_keys=False)
return result
#TODO: a single Fixture or a list of Fixtures for each model?
return Fixture(
model_backup=self,
content=command.handle(u' '.join(result), format='json', indent=4, using=DEFAULT_DB_ALIAS, exclude=[], user_base_manager=False, use_natural_keys=False)
)
class ElementBackupFile(ElementBackupBase):
class FileBackup(ElementBackupBase):
label = _(u'File copy')
def __init__(self, storage_class, filepath=None):
@@ -68,6 +111,7 @@ class ElementBackupFile(ElementBackupBase):
return None
# App config
class AppBackup(object):
_registry = {}
@@ -89,6 +133,10 @@ class AppBackup(object):
def get_all(cls):
return cls._registry.values()
@classmethod
def get_as_choices(cls):
return [(key, key.label) for key, values in cls._registry.items()]
def __init__(self, name, label, backup_managers):
self.label = label
self.name = name
@@ -102,14 +150,17 @@ class AppBackup(object):
results.append(u'%s - %s' % (manager, manager.info() or _(u'Nothing')))
return u', '.join(results)
def backup(self, storage_module, *args, **kwargs):
def backup(self, storage_module, dry_run=False):
logger.debug('starting')
self.state = self.__class__.STATE_BACKING_UP
for manager in self.backup_managers:
result = manager.backup()
storage_module.backup(result)
storage_module.backup(result, dry_run=dry_run)
self.state = self.__class__.STATE_IDLE
def restore(self, storage_module=None):
logger.debug('starting')
self.state = self.__class__.STATE_RESTORING
for manager in self.backup_managers:
manager.restore(storage_module.restore())
@@ -119,8 +170,9 @@ class AppBackup(object):
return unicode(self.label)
#Storage
class StorageModuleBase(object):
_registry = []
_registry = {}
# Local modules depend on hardware on a node and execute in the Scheduler
# of a particular node
@@ -135,16 +187,34 @@ class StorageModuleBase(object):
(REALM_REMOTE, _(u'remote')),
)
class UnknownStorageModule(Exception):
pass
@classmethod
def register(cls, klass):
"""
Register a subclass of StorageModuleBase to make it available to the
UI
"""
cls._registry.append(klass)
cls._registry[klass.name] = klass
def __init__(self, *args, **kwargs):
pass
@classmethod
def get_all(cls):
return cls._registry.values()
@classmethod
def get(cls, name):
try:
return cls._registry[name]
except KeyError:
raise cls.UnknownStorageModule
@classmethod
def get_as_choices(cls):
return cls._registry.items()
def get_arguments(self):
return []
def is_local_realm(self):
return self.realm == REALM_LOCAL
@@ -152,7 +222,7 @@ class StorageModuleBase(object):
def is_remote_realm(self):
return self.realm == REALM_REMOTE
def backup(self, data):
def backup(self, data, dry_run):
raise NotImplemented
def restore(self):
@@ -160,18 +230,24 @@ class StorageModuleBase(object):
Must return data or a file like object
"""
raise NotImplemented
def __unicode__(self):
return unicode(self.label)
class TestStorageModule(StorageModuleBase):
name = 'test_storage'
label = _(u'Test storage module')
realm = StorageModuleBase.REALM_LOCAL
def __init__(self, *args, **kwargs):
self.backup_path = kwargs.pop('backup_path', None)
self.restore_path = kwargs.pop('restore_path', None)
return super(TestStorageModule, self).__init__(*args, **kwargs)
def get_arguments(self):
return ['backup_path', 'restore_path']
def backup(self, data):
def backup(self, data, dry_run):
print '***** received data'
print data
print '***** saving to path: %s' % self.backup_path