Skip to content

Commit

Permalink
Add snapshots to the volume usage audit report
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Michael Kerrin committed Mar 19, 2013
1 parent 7bb449a commit f117a0e
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 3 deletions.
20 changes: 20 additions & 0 deletions bin/cinder-volume-usage-audit
Expand Up @@ -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)
Expand All @@ -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")
7 changes: 7 additions & 0 deletions cinder/db/api.py
Expand Up @@ -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)


####################


Expand Down
16 changes: 16 additions & 0 deletions cinder/db/sqlalchemy/api.py
Expand Up @@ -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()
Expand Down
153 changes: 153 additions & 0 deletions cinder/tests/test_volume.py
Expand Up @@ -857,6 +857,159 @@ def test_volume_api_update_snapshot(self):
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."""
Expand Down
39 changes: 36 additions & 3 deletions cinder/volume/utils.py
Expand Up @@ -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'],
Expand Down Expand Up @@ -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)

0 comments on commit f117a0e

Please sign in to comment.