Adding a running method to the Backup Model

* Adds a query classmethod to Base Model for
  more complex queries such 'in_'
* Adds a running classmethod to Backup Model
  which returns any currently running backups
  for an instance.
* Add a checksum field to the Backup Model.
* Refactor the DBBackup to reuse base methods

Change-Id: Iaf6903af88c7f4caa20921f1ca63354999ec6348
This commit is contained in:
Robert Myers
2013-04-03 11:10:24 -05:00
parent 8d89bae2ad
commit 817e2d6eea
4 changed files with 97 additions and 24 deletions

View File

@@ -16,10 +16,7 @@
from reddwarf.common import cfg
from reddwarf.common import exception
from reddwarf.common import utils
from reddwarf.db.models import DatabaseModelBase
from reddwarf.openstack.common import log as logging
CONF = cfg.CONF
@@ -33,6 +30,8 @@ class BackupState(object):
SAVING = "SAVING"
COMPLETED = "COMPLETED"
FAILED = "FAILED"
RUNNING_STATES = [NEW, BUILDING, SAVING]
END_STATES = [COMPLETED, FAILED]
class Backup(object):
@@ -60,6 +59,37 @@ class Backup(object):
LOG.exception("Unable to create Backup record:")
raise exception.BackupCreationError(str(ex))
@classmethod
def running(cls, instance_id, exclude=None):
"""
Returns the first running backup for instance_id
:param instance_id: Id of the instance
:param exclude: Backup ID to exclude from the query (any other running)
"""
query = DBBackup.query()
query = query.filter(DBBackup.instance_id == instance_id,
DBBackup.state.in_(BackupState.RUNNING_STATES))
# filter out deleted backups, PEP8 does not like field == False!
query = query.filter_by(deleted=False)
if exclude:
query = query.filter(DBBackup.id != exclude)
return query.first()
@classmethod
def get_by_id(cls, backup_id, deleted=False):
"""
get the backup for that id
:param cls:
:param backup_id: Id of the backup to return
:param deleted: Return deleted backups
:return:
"""
try:
db_info = DBBackup.find_by(id=backup_id, deleted=deleted)
return db_info
except exception.NotFound:
raise exception.NotFound(uuid=backup_id)
@classmethod
def list(cls, context):
"""
@@ -85,22 +115,17 @@ class Backup(object):
return db_info
@classmethod
def delete(cls, id):
def delete(cls, backup_id):
"""
update Backup table on deleted flag for given Backup
:param cls:
:param id: Backup uuid
:param backup_id: Backup uuid
:return:
"""
#TODO: api (service.py) might take care of actual deletion
# on remote swift
try:
db_info = DBBackup.find_by(id=id, deleted=False)
db_info.update(deleted=True, deleted_at=utils.utcnow())
except exception.ReddwarfError as ex:
LOG.exception("Backup record cannot be updated for "
"backup %s :") % id
raise exception.BackupUpdateError(str(ex))
db_info = cls.get_by_id(backup_id)
db_info.delete()
def persisted_models():
@@ -111,5 +136,14 @@ class DBBackup(DatabaseModelBase):
"""A table for Backup records"""
_data_fields = ['id', 'name', 'description', 'location', 'backup_type',
'size', 'tenant_id', 'state', 'instance_id',
'backup_timestamp', 'deleted', 'created',
'checksum', 'backup_timestamp', 'deleted', 'created',
'updated', 'deleted_at']
preserve_on_delete = True
@property
def is_running(self):
return self.state in BackupState.RUNNING_STATES
@property
def is_done(self):
return self.state in BackupState.END_STATES

View File

@@ -47,6 +47,10 @@ class DatabaseModelBase(models.ModelBase):
def preserve_on_delete(self):
return hasattr(self, 'deleted') and hasattr(self, 'deleted_at')
@classmethod
def query(cls):
return get_db_api()._base_query(cls)
def save(self):
if not self.is_valid():
raise exception.InvalidModelError(errors=self.errors)

View File

@@ -36,6 +36,7 @@ backups = Table('backups', meta,
Column('tenant_id', String(36)),
Column('state', String(32), nullable=False),
Column('instance_id', String(36)),
Column('checksum', String(32)),
Column('backup_timestamp', DateTime()),
Column('deleted', Boolean()),
Column('created', DateTime()),

View File

@@ -57,11 +57,11 @@ class BackupORMTest(testtools.TestCase):
super(BackupORMTest, self).setUp()
util.init_db()
self.context, self.instance_id = _prep_conf(utils.utcnow())
models.DBBackup.create(tenant_id=self.context.tenant,
name=BACKUP_NAME,
state=BACKUP_STATE,
instance_id=self.instance_id,
deleted=False)
self.backup = models.DBBackup.create(tenant_id=self.context.tenant,
name=BACKUP_NAME,
state=BACKUP_STATE,
instance_id=self.instance_id,
deleted=False)
self.deleted = False
def tearDown(self):
@@ -82,11 +82,45 @@ class BackupORMTest(testtools.TestCase):
db_record = models.Backup.list_for_instance(self.instance_id)
self.assertEqual(2, db_record.count())
def test_running(self):
running = models.Backup.running(instance_id=self.instance_id)
self.assertTrue(running)
def test_not_running(self):
not_running = models.Backup.running(instance_id='non-existent')
self.assertFalse(not_running)
def test_running_exclude(self):
not_running = models.Backup.running(instance_id=self.instance_id,
exclude=self.backup.id)
self.assertFalse(not_running)
def test_is_running(self):
self.assertTrue(self.backup.is_running)
def test_is_done(self):
self.backup.state = models.BackupState.COMPLETED
self.backup.save()
self.assertTrue(self.backup.is_done)
def test_not_is_running(self):
self.backup.state = models.BackupState.COMPLETED
self.backup.save()
self.assertFalse(self.backup.is_running)
def test_not_is_done(self):
self.assertFalse(self.backup.is_done)
def test_backup_delete(self):
models.Backup.delete(self.backup.id)
query = models.Backup.list_for_instance(self.instance_id)
self.assertEqual(query.count(), 0)
def test_delete(self):
db_record = models.DBBackup.find_by(tenant_id=self.context.tenant)
uuid = db_record['id']
print uuid
models.Backup.delete(uuid)
self.deleted = True
db_record = models.DBBackup.find_by(id=uuid, deleted=True)
self.backup.delete()
db_record = models.DBBackup.find_by(id=self.backup.id, deleted=True)
self.assertEqual(self.instance_id, db_record['instance_id'])
def test_deleted_not_running(self):
self.backup.delete()
self.assertFalse(models.Backup.running(self.instance_id))