Add snapshots to the volume usage audit report

* Added tests for db api call volume_get_active_by_window called by the volume
usage audit report.

* Added new db api called snapshot_get_active_by_window & test it. This is
similar to the volume_get_active_by_window method but returns the snapshots
 active the supplied time window.

* Integrate the above into the cinder-volume-usage-audit script to report on
  all the active snapshots as well as volumes in the specified time frame.

Fixes: bug #1157110

Change-Id: I7597da20c62150a8f6c74cbfeec159f68064d2a6
This commit is contained in:
Michael Kerrin 2013-03-19 18:04:39 +00:00
parent 7bb449aa5a
commit f117a0e22a
5 changed files with 232 additions and 3 deletions

View File

@ -67,6 +67,12 @@ if __name__ == '__main__':
print _("Starting volume usage audit")
msg = _("Creating usages for %(begin_period)s until %(end_period)s")
print (msg % {"begin_period": str(begin), "end_period": str(end)})
extra_info = {
'audit_period_beginning': str(begin),
'audit_period_ending': str(end),
}
volumes = db.volume_get_active_by_window(admin_context,
begin,
end)
@ -77,4 +83,18 @@ if __name__ == '__main__':
admin_context, volume_ref)
except Exception, e:
print traceback.format_exc(e)
snapshots = db.snapshot_get_active_by_window(admin_context,
begin,
end)
print _("Found %d snapshots") % len(snapshots)
for snapshot_ref in snapshots:
try:
cinder.volume.utils.notify_about_snapshot_usage(admin_context,
snapshot_ref,
'exists',
extra_info)
except Exception, e:
print traceback.fromat_exc(e)
print _("Volume usage audit completed")

View File

@ -317,6 +317,13 @@ def snapshot_data_get_for_project(context, project_id, session=None):
session=None)
def snapshot_get_active_by_window(context, begin, end=None, project_id=None):
"""Get all the snapshots inside the window.
Specifying a project_id will filter for a certain project."""
return IMPL.snapshot_get_active_by_window(context, begin, end, project_id)
####################

View File

@ -1260,6 +1260,22 @@ def snapshot_data_get_for_project(context, project_id, session=None):
return (result[0] or 0, result[1] or 0)
@require_context
def snapshot_get_active_by_window(context, begin, end=None, project_id=None):
"""Return snapshots that were active during window."""
session = get_session()
query = session.query(models.Snapshot)
query = query.filter(or_(models.Snapshot.deleted_at == None,
models.Snapshot.deleted_at > begin))
if end:
query = query.filter(models.Snapshot.created_at < end)
if project_id:
query = query.filter_by(project_id=project_id)
return query.all()
@require_context
def snapshot_update(context, snapshot_id, values):
session = get_session()

View File

@ -857,6 +857,159 @@ class VolumeTestCase(test.TestCase):
snap = db.snapshot_get(context.get_admin_context(), snapshot['id'])
self.assertEquals(snap['display_name'], 'test update name')
def test_volume_get_active_by_window(self):
# Find all all volumes valid within a timeframe window.
try: # Not in window
db.volume_create(
self.context,
{
'id': 1,
'host': 'devstack',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': True, 'status': 'deleted',
'deleted_at': datetime.datetime(1, 2, 1, 1, 1, 1),
}
)
except exception.VolumeNotFound:
pass
try: # In - deleted in window
db.volume_create(
self.context,
{
'id': 2,
'host': 'devstack',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': True, 'status': 'deleted',
'deleted_at': datetime.datetime(1, 3, 10, 1, 1, 1),
}
)
except exception.VolumeNotFound:
pass
try: # In - deleted after window
db.volume_create(
self.context,
{
'id': 3,
'host': 'devstack',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': True, 'status': 'deleted',
'deleted_at': datetime.datetime(1, 5, 1, 1, 1, 1),
}
)
except exception.VolumeNotFound:
pass
# In - created in window
db.volume_create(
self.context,
{
'id': 4,
'host': 'devstack',
'created_at': datetime.datetime(1, 3, 10, 1, 1, 1),
}
)
# Not of window.
db.volume_create(
self.context,
{
'id': 5,
'host': 'devstack',
'created_at': datetime.datetime(1, 5, 1, 1, 1, 1),
}
)
volumes = db.volume_get_active_by_window(
self.context,
datetime.datetime(1, 3, 1, 1, 1, 1),
datetime.datetime(1, 4, 1, 1, 1, 1))
self.assertEqual(len(volumes), 3)
self.assertEqual(volumes[0].id, u'2')
self.assertEqual(volumes[1].id, u'3')
self.assertEqual(volumes[2].id, u'4')
def test_snapshot_get_active_by_window(self):
# Find all all snapshots valid within a timeframe window.
vol = db.volume_create(self.context, {'id': 1})
try: # Not in window
db.snapshot_create(
self.context,
{
'id': 1,
'host': 'devstack',
'volume_id': 1,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': True, 'status': 'deleted',
'deleted_at': datetime.datetime(1, 2, 1, 1, 1, 1),
}
)
except exception.SnapshotNotFound:
pass
try: # In - deleted in window
db.snapshot_create(
self.context,
{
'id': 2,
'host': 'devstack',
'volume_id': 1,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': True, 'status': 'deleted',
'deleted_at': datetime.datetime(1, 3, 10, 1, 1, 1),
}
)
except exception.SnapshotNotFound:
pass
try: # In - deleted after window
db.snapshot_create(
self.context,
{
'id': 3,
'host': 'devstack',
'volume_id': 1,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'deleted': True, 'status': 'deleted',
'deleted_at': datetime.datetime(1, 5, 1, 1, 1, 1),
}
)
except exception.SnapshotNotFound:
pass
# In - created in window
db.snapshot_create(
self.context,
{
'id': 4,
'host': 'devstack',
'volume_id': 1,
'created_at': datetime.datetime(1, 3, 10, 1, 1, 1),
}
)
# Not of window.
db.snapshot_create(
self.context,
{
'id': 5,
'host': 'devstack',
'volume_id': 1,
'created_at': datetime.datetime(1, 5, 1, 1, 1, 1),
}
)
snapshots = db.snapshot_get_active_by_window(
self.context,
datetime.datetime(1, 3, 1, 1, 1, 1),
datetime.datetime(1, 4, 1, 1, 1, 1))
self.assertEqual(len(snapshots), 3)
self.assertEqual(snapshots[0].id, u'2')
self.assertEqual(snapshots[1].id, u'3')
self.assertEqual(snapshots[2].id, u'4')
class DriverTestCase(test.TestCase):
"""Base Test class for Drivers."""

View File

@ -54,10 +54,11 @@ def notify_usage_exists(context, volume_ref, current_period=False):
'exists', extra_usage_info=extra_usage_info)
def _usage_from_volume(context, volume_ref, **kw):
def null_safe_str(s):
return str(s) if s else ''
def null_safe_str(s):
return str(s) if s else ''
def _usage_from_volume(context, volume_ref, **kw):
usage_info = dict(tenant_id=volume_ref['project_id'],
user_id=volume_ref['user_id'],
volume_id=volume_ref['id'],
@ -86,3 +87,35 @@ def notify_about_volume_usage(context, volume, event_suffix,
notifier_api.notify(context, 'volume.%s' % host,
'volume.%s' % event_suffix,
notifier_api.INFO, usage_info)
def _usage_from_snapshot(context, snapshot_ref, **extra_usage_info):
usage_info = {
'tenant_id': snapshot_ref['project_id'],
'user_id': snapshot_ref['user_id'],
'volume_id': snapshot_ref['volume_id'],
'volume_size': snapshot_ref['volume_size'],
'snapshot_id': snapshot_ref['id'],
'display_name': snapshot_ref['display_name'],
'created_at': str(snapshot_ref['created_at']),
'status': snapshot_ref['status'],
'deleted': null_safe_str(snapshot_ref['deleted'])
}
usage_info.update(extra_usage_info)
return usage_info
def notify_about_snapshot_usage(context, snapshot, event_suffix,
extra_usage_info=None, host=None):
if not host:
host = FLAGS.host
if not extra_usage_info:
extra_usage_info = {}
usage_info = _usage_from_snapshot(context, snapshot, **extra_usage_info)
notifier_api.notify(context, 'snapshot.%s' % host,
'snapshot.%s' % event_suffix,
notifier_api.INFO, usage_info)