Add backup notification to cinder-volume-usage-audit

Change-Id: I92ea83870bce916eab0c564f88887df69231652c
Closes-Bug: #1628515
This commit is contained in:
Bartek Zurawski 2016-09-29 15:42:35 +00:00
parent ecb3e13097
commit ebcf4fb165
6 changed files with 266 additions and 2 deletions

View File

@ -246,4 +246,75 @@ def main():
LOG.exception(_LE("Delete snapshot notification failed: %s"),
exc_msg, resource=snapshot_ref)
backups = db.backup_get_active_by_window(admin_context,
begin, end)
LOG.debug("Found %d backups", len(backups))
for backup_ref in backups:
try:
LOG.debug("Send notification for <backup_id: %(backup_id)s> "
"<project_id %(project_id)s> <%(extra_info)s>",
{'backup_id': backup_ref.id,
'project_id': backup_ref.project_id,
'extra_info': extra_info})
cinder.volume.utils.notify_about_backup_usage(admin_context,
backup_ref,
'exists',
extra_info)
except Exception as exc_msg:
LOG.error(_LE("Exists backups notification failed: %s"),
exc_msg)
if (CONF.send_actions and
backup_ref.created_at > begin and
backup_ref.created_at < end):
try:
local_extra_info = {
'audit_period_beginning': str(backup_ref.created_at),
'audit_period_ending': str(backup_ref.created_at),
}
LOG.debug("Send create notification for "
"<backup_id: %(backup_id)s> "
"<project_id %(project_id)s> <%(extra_info)s>",
{'backup_id': backup_ref.id,
'project_id': backup_ref.project_id,
'extra_info': local_extra_info})
cinder.volume.utils.notify_about_backup_usage(
admin_context,
backup_ref,
'create.start', extra_usage_info=local_extra_info)
cinder.volume.utils.notify_about_backup_usage(
admin_context,
backup_ref,
'create.end', extra_usage_info=local_extra_info)
except Exception as exc_msg:
LOG.error(_LE("Create backup notification failed: %s"),
exc_msg)
if (CONF.send_actions and backup_ref.deleted_at and
backup_ref.deleted_at > begin and
backup_ref.deleted_at < end):
try:
local_extra_info = {
'audit_period_beginning': str(backup_ref.deleted_at),
'audit_period_ending': str(backup_ref.deleted_at),
}
LOG.debug("Send delete notification for "
"<backup_id: %(backup_id)s> "
"<project_id %(project_id)s> <%(extra_info)s>",
{'backup_id': backup_ref.id,
'project_id': backup_ref.project_id,
'extra_info': local_extra_info})
cinder.volume.utils.notify_about_backup_usage(
admin_context,
backup_ref,
'delete.start', extra_usage_info=local_extra_info)
cinder.volume.utils.notify_about_backup_usage(
admin_context,
backup_ref,
'delete.end', extra_usage_info=local_extra_info)
except Exception as exc_msg:
LOG.error(_LE("Delete backup notification failed: %s"),
exc_msg)
LOG.debug("Volume usage audit completed")

View File

@ -1155,6 +1155,14 @@ def backup_get_all_by_volume(context, volume_id, filters=None):
filters=filters)
def backup_get_active_by_window(context, begin, end=None, project_id=None):
"""Get all the backups inside the window.
Specifying a project_id will filter for a certain project.
"""
return IMPL.backup_get_active_by_window(context, begin, end, project_id)
def backup_update(context, backup_id, values):
"""Set the given properties on a backup and update it.

View File

@ -4696,6 +4696,21 @@ def backup_get_all_by_volume(context, volume_id, filters=None):
return _backup_get_all(context, filters)
@require_context
def backup_get_active_by_window(context, begin, end=None, project_id=None):
"""Return backups that were active during window."""
query = model_query(context, models.Backup, read_deleted="yes")
query = query.filter(or_(models.Backup.deleted_at == None, # noqa
models.Backup.deleted_at > begin))
if end:
query = query.filter(models.Backup.created_at < end)
if project_id:
query = query.filter_by(project_id=project_id)
return query.all()
@handle_db_data_error
@require_context
def backup_create(context, values):

View File

@ -20,6 +20,8 @@ ATTACHMENT2_ID = 'ac2439fe-c071-468f-94e3-547bedb95de0'
BACKUP_ID = '707844eb-6d8a-4ac1-8b98-618e1c0b3a3a'
BACKUP2_ID = '40e8462a-c9d8-462f-a810-b732a1790535'
BACKUP3_ID = '30ae7641-017e-4221-a642-855687c8bd71'
BACKUP4_ID = '23f8605b-8273-4f49-9b3d-1eeca81a63c2'
BACKUP5_ID = '50c97b22-51ea-440b-8d01-ded20a55d7e0'
CGSNAPSHOT_ID = '5e34cce3-bc97-46b7-a127-5cfb95ef445d'
CGSNAPSHOT_NAME = 'cgsnapshot-5e34cce3-bc97-46b7-a127-5cfb95ef445d'
CGSNAPSHOT2_ID = '5c36d762-d6ba-4f04-bd07-88a298cc410a'

View File

@ -1907,6 +1907,72 @@ class TestCinderVolumeUsageAuditCmd(test.TestCase):
extra_usage_info=local_extra_info_delete)
])
@mock.patch('cinder.volume.utils.notify_about_backup_usage')
@mock.patch('cinder.db.backup_get_active_by_window')
@mock.patch('cinder.volume.utils.notify_about_volume_usage')
@mock.patch('cinder.db.volume_get_active_by_window')
@mock.patch('cinder.utils.last_completed_audit_period')
@mock.patch('cinder.rpc.init')
@mock.patch('cinder.version.version_string')
@mock.patch('cinder.context.get_admin_context')
def test_main_send_backup_error(self, get_admin_context,
version_string, rpc_init,
last_completed_audit_period,
volume_get_active_by_window,
notify_about_volume_usage,
backup_get_active_by_window,
notify_about_backup_usage):
CONF.set_override('send_actions', True)
CONF.set_override('start_time', '2014-01-01 01:00:00')
CONF.set_override('end_time', '2014-02-02 02:00:00')
begin = datetime.datetime(2014, 1, 1, 1, 0)
end = datetime.datetime(2014, 2, 2, 2, 0)
ctxt = context.RequestContext('fake-user', 'fake-project')
get_admin_context.return_value = ctxt
last_completed_audit_period.return_value = (begin, end)
backup1_created = datetime.datetime(2014, 1, 1, 2, 0)
backup1_deleted = datetime.datetime(2014, 1, 1, 3, 0)
backup1 = mock.MagicMock(id=fake.BACKUP_ID,
project_id=fake.PROJECT_ID,
created_at=backup1_created,
deleted_at=backup1_deleted)
volume_get_active_by_window.return_value = []
backup_get_active_by_window.return_value = [backup1]
extra_info = {
'audit_period_beginning': str(begin),
'audit_period_ending': str(end),
}
local_extra_info_create = {
'audit_period_beginning': str(backup1.created_at),
'audit_period_ending': str(backup1.created_at),
}
local_extra_info_delete = {
'audit_period_beginning': str(backup1.deleted_at),
'audit_period_ending': str(backup1.deleted_at),
}
notify_about_backup_usage.side_effect = Exception()
volume_usage_audit.main()
get_admin_context.assert_called_once_with()
self.assertEqual('cinder', CONF.project)
self.assertEqual(CONF.version, version.version_string())
rpc_init.assert_called_once_with(CONF)
last_completed_audit_period.assert_called_once_with()
volume_get_active_by_window.assert_called_once_with(ctxt, begin, end)
self.assertFalse(notify_about_volume_usage.called)
notify_about_backup_usage.assert_any_call(ctxt, backup1, 'exists',
extra_info)
notify_about_backup_usage.assert_any_call(
ctxt, backup1, 'create.start',
extra_usage_info=local_extra_info_create)
notify_about_backup_usage.assert_any_call(
ctxt, backup1, 'delete.start',
extra_usage_info=local_extra_info_delete)
@mock.patch('cinder.volume.utils.notify_about_backup_usage')
@mock.patch('cinder.db.backup_get_active_by_window')
@mock.patch('cinder.volume.utils.notify_about_snapshot_usage')
@mock.patch('cinder.objects.snapshot.SnapshotList.get_active_by_window')
@mock.patch('cinder.volume.utils.notify_about_volume_usage')
@ -1920,7 +1986,8 @@ class TestCinderVolumeUsageAuditCmd(test.TestCase):
def test_main(self, get_admin_context, log_setup, get_logger,
version_string, rpc_init, last_completed_audit_period,
volume_get_active_by_window, notify_about_volume_usage,
snapshot_get_active_by_window, notify_about_snapshot_usage):
snapshot_get_active_by_window, notify_about_snapshot_usage,
backup_get_active_by_window, notify_about_backup_usage):
CONF.set_override('send_actions', True)
CONF.set_override('start_time', '2014-01-01 01:00:00')
CONF.set_override('end_time', '2014-02-02 02:00:00')
@ -1965,6 +2032,22 @@ class TestCinderVolumeUsageAuditCmd(test.TestCase):
'audit_period_ending': str(snapshot1.deleted_at),
}
backup1_created = datetime.datetime(2014, 1, 1, 2, 0)
backup1_deleted = datetime.datetime(2014, 1, 1, 3, 0)
backup1 = mock.MagicMock(id=fake.BACKUP_ID,
project_id=fake.PROJECT_ID,
created_at=backup1_created,
deleted_at=backup1_deleted)
backup_get_active_by_window.return_value = [backup1]
extra_info_backup_create = {
'audit_period_beginning': str(backup1.created_at),
'audit_period_ending': str(backup1.created_at),
}
extra_info_backup_delete = {
'audit_period_beginning': str(backup1.deleted_at),
'audit_period_ending': str(backup1.deleted_at),
}
volume_usage_audit.main()
get_admin_context.assert_called_once_with()
@ -1998,3 +2081,15 @@ class TestCinderVolumeUsageAuditCmd(test.TestCase):
mock.call(ctxt, snapshot1, 'delete.end',
extra_usage_info=extra_info_snapshot_delete)
])
notify_about_backup_usage.assert_has_calls([
mock.call(ctxt, backup1, 'exists', extra_info),
mock.call(ctxt, backup1, 'create.start',
extra_usage_info=extra_info_backup_create),
mock.call(ctxt, backup1, 'create.end',
extra_usage_info=extra_info_backup_create),
mock.call(ctxt, backup1, 'delete.start',
extra_usage_info=extra_info_backup_delete),
mock.call(ctxt, backup1, 'delete.end',
extra_usage_info=extra_info_backup_delete)
])

View File

@ -5929,7 +5929,6 @@ class GetActiveByWindowTestCase(BaseVolumeTestCase):
'deleted': True, 'status': 'deleted',
'deleted_at': datetime.datetime(1, 2, 1, 1, 1, 1),
},
{
'id': fake.VOLUME2_ID,
'host': 'devstack',
@ -6003,6 +6002,48 @@ class GetActiveByWindowTestCase(BaseVolumeTestCase):
}
]
self.db_back_attrs = [
{
'id': fake.BACKUP_ID,
'host': 'devstack',
'project_id': fake.PROJECT_ID,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': 1,
'status': 'deleted',
'deleted_at': datetime.datetime(1, 2, 1, 1, 1, 1)
},
{
'id': fake.BACKUP2_ID,
'host': 'devstack',
'project_id': fake.PROJECT_ID,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': 1,
'status': 'deleted',
'deleted_at': datetime.datetime(1, 3, 10, 1, 1, 1)
},
{
'id': fake.BACKUP3_ID,
'host': 'devstack',
'project_id': fake.PROJECT_ID,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': 1,
'status': 'deleted',
'deleted_at': datetime.datetime(1, 5, 1, 1, 1, 1)
},
{
'id': fake.BACKUP4_ID,
'host': 'devstack',
'project_id': fake.PROJECT_ID,
'created_at': datetime.datetime(1, 3, 10, 1, 1, 1),
},
{
'id': fake.BACKUP5_ID,
'host': 'devstack',
'project_id': fake.PROJECT_ID,
'created_at': datetime.datetime(1, 5, 1, 1, 1, 1),
},
]
def test_volume_get_active_by_window(self):
# Find all all volumes valid within a timeframe window.
@ -6074,6 +6115,38 @@ class GetActiveByWindowTestCase(BaseVolumeTestCase):
self.assertEqual(snap4.id, snapshots[2].id)
self.assertEqual(fake.VOLUME_ID, snapshots[2].volume_id)
def test_backup_get_active_by_window(self):
# Find all backups valid within a timeframe window.
db.volume_create(self.context, {'id': fake.VOLUME_ID})
for i in range(5):
self.db_back_attrs[i]['volume_id'] = fake.VOLUME_ID
# Not in window
db.backup_create(self.ctx, self.db_back_attrs[0])
# In - deleted in window
db.backup_create(self.ctx, self.db_back_attrs[1])
# In - deleted after window
db.backup_create(self.ctx, self.db_back_attrs[2])
# In - created in window
db.backup_create(self.ctx, self.db_back_attrs[3])
# Not of window
db.backup_create(self.ctx, self.db_back_attrs[4])
backups = db.backup_get_active_by_window(
self.context,
datetime.datetime(1, 3, 1, 1, 1, 1),
datetime.datetime(1, 4, 1, 1, 1, 1),
project_id=fake.PROJECT_ID
)
self.assertEqual(3, len(backups))
self.assertEqual(fake.BACKUP2_ID, backups[0].id)
self.assertEqual(fake.BACKUP3_ID, backups[1].id)
self.assertEqual(fake.BACKUP4_ID, backups[2].id)
class DriverTestCase(test.TestCase):
"""Base Test class for Drivers."""