Adding notifications for volumes
Added notifications for volumes have been added with tests. This includes create/delete/exists events for volumes. blueprint nova-notifications Change-Id: I21b74974fac22c3621ccf7564dc5c0d339f8751a
This commit is contained in:
1
Authors
1
Authors
@@ -40,6 +40,7 @@ Chuck Short <zulcss@ubuntu.com>
|
||||
Cole Robinson <crobinso@redhat.com>
|
||||
Cor Cornelisse <cor@hyves.nl>
|
||||
Cory Wright <corywright@gmail.com>
|
||||
Craig Vyvial <cp16net@gmail.com>
|
||||
Dan Prince <dprince@redhat.com>
|
||||
Dan Wendlandt <dan@nicira.com>
|
||||
Daniel P. Berrange <berrange@redhat.com>
|
||||
|
@@ -16,8 +16,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Cron script to generate usage notifications for instances neither created
|
||||
nor destroyed in a given time period.
|
||||
"""Cron script to generate usage notifications for instances existing
|
||||
during the audit period.
|
||||
|
||||
Together with the notifications generated by compute on instance
|
||||
create/delete/resize, over that time period, this allows an external
|
||||
|
84
bin/volume-usage-audit
Executable file
84
bin/volume-usage-audit
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright (c) 2011 Openstack, LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Cron script to generate usage notifications for volumes existing during
|
||||
the audit period.
|
||||
|
||||
Together with the notifications generated by volumes
|
||||
create/delete/resize, over that time period, this allows an external
|
||||
system consuming usage notification feeds to calculate volume usage
|
||||
for each tenant.
|
||||
|
||||
Time periods are specified as 'hour', 'month', 'day' or 'year'
|
||||
|
||||
hour = previous hour. If run at 9:07am, will generate usage for 8-9am.
|
||||
month = previous month. If the script is run April 1, it will generate
|
||||
usages for March 1 through March 31.
|
||||
day = previous day. if run on July 4th, it generates usages for July 3rd.
|
||||
year = previous year. If run on Jan 1, it generates usages for
|
||||
Jan 1 through Dec 31 of the previous year.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import gettext
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
|
||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||
POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')):
|
||||
sys.path.insert(0, POSSIBLE_TOPDIR)
|
||||
|
||||
gettext.install('nova', unicode=1)
|
||||
from nova import context
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import rpc
|
||||
from nova import utils
|
||||
import nova.volume.utils
|
||||
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
if __name__ == '__main__':
|
||||
rpc.register_opts(FLAGS)
|
||||
admin_context = context.get_admin_context()
|
||||
utils.default_flagfile()
|
||||
flags.FLAGS(sys.argv)
|
||||
logging.setup()
|
||||
begin, end = utils.last_completed_audit_period()
|
||||
print "Starting volume usage audit"
|
||||
print "Creating usages for %s until %s" % (str(begin), str(end))
|
||||
volumes = db.volume_get_active_by_window(admin_context,
|
||||
begin,
|
||||
end)
|
||||
print "Found %d volumes" % len(volumes)
|
||||
for volume_ref in volumes:
|
||||
try:
|
||||
nova.volume.utils.notify_usage_exists(
|
||||
admin_context, volume_ref)
|
||||
except Exception, e:
|
||||
print traceback.format_exc(e)
|
||||
print "Volume usage audit completed"
|
@@ -29,6 +29,7 @@ from nova import exception
|
||||
from nova import db
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova.notifier import test_notifier
|
||||
from nova.openstack.common import importutils
|
||||
import nova.policy
|
||||
from nova import rpc
|
||||
@@ -46,18 +47,21 @@ class VolumeTestCase(test.TestCase):
|
||||
super(VolumeTestCase, self).setUp()
|
||||
self.compute = importutils.import_object(FLAGS.compute_manager)
|
||||
self.flags(connection_type='fake')
|
||||
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
|
||||
'nova.notifier.test_notifier')
|
||||
self.volume = importutils.import_object(FLAGS.volume_manager)
|
||||
self.context = context.get_admin_context()
|
||||
instance = db.instance_create(self.context, {})
|
||||
self.instance_id = instance['id']
|
||||
self.instance_uuid = instance['uuid']
|
||||
test_notifier.NOTIFICATIONS = []
|
||||
|
||||
def tearDown(self):
|
||||
db.instance_destroy(self.context, self.instance_id)
|
||||
super(VolumeTestCase, self).tearDown()
|
||||
|
||||
@staticmethod
|
||||
def _create_volume(size='0', snapshot_id=None):
|
||||
def _create_volume(size=0, snapshot_id=None):
|
||||
"""Create a volume object."""
|
||||
vol = {}
|
||||
vol['size'] = size
|
||||
@@ -88,11 +92,14 @@ class VolumeTestCase(test.TestCase):
|
||||
"""Test volume can be created and deleted."""
|
||||
volume = self._create_volume()
|
||||
volume_id = volume['id']
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
|
||||
self.volume.create_volume(self.context, volume_id)
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 2)
|
||||
self.assertEqual(volume_id, db.volume_get(context.get_admin_context(),
|
||||
volume_id).id)
|
||||
|
||||
self.volume.delete_volume(self.context, volume_id)
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 4)
|
||||
self.assertRaises(exception.NotFound,
|
||||
db.volume_get,
|
||||
self.context,
|
||||
@@ -363,6 +370,30 @@ class VolumeTestCase(test.TestCase):
|
||||
self.volume.delete_snapshot(self.context, snapshot_id)
|
||||
self.volume.delete_volume(self.context, volume_id)
|
||||
|
||||
def test_create_volume_usage_notification(self):
|
||||
"""Ensure create volume generates appropriate usage notification"""
|
||||
volume = self._create_volume()
|
||||
volume_id = volume['id']
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
|
||||
self.volume.create_volume(self.context, volume_id)
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 2)
|
||||
msg = test_notifier.NOTIFICATIONS[0]
|
||||
self.assertEquals(msg['event_type'], 'volume.create.start')
|
||||
msg = test_notifier.NOTIFICATIONS[1]
|
||||
self.assertEquals(msg['priority'], 'INFO')
|
||||
self.assertEquals(msg['event_type'], 'volume.create.end')
|
||||
payload = msg['payload']
|
||||
self.assertEquals(payload['tenant_id'], volume['project_id'])
|
||||
self.assertEquals(payload['user_id'], volume['user_id'])
|
||||
self.assertEquals(payload['volume_id'], volume['id'])
|
||||
self.assertEquals(payload['status'], 'creating')
|
||||
self.assertEquals(payload['size'], volume['size'])
|
||||
self.assertTrue('display_name' in payload)
|
||||
self.assertTrue('snapshot_id' in payload)
|
||||
self.assertTrue('launched_at' in payload)
|
||||
self.assertTrue('created_at' in payload)
|
||||
self.volume.delete_volume(self.context, volume_id)
|
||||
|
||||
|
||||
class DriverTestCase(test.TestCase):
|
||||
"""Base Test class for Drivers."""
|
||||
|
86
nova/tests/test_volume_utils.py
Normal file
86
nova/tests/test_volume_utils.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests For miscellaneous util methods used with volume."""
|
||||
|
||||
from nova import db
|
||||
from nova import flags
|
||||
from nova import context
|
||||
from nova import test
|
||||
from nova import log as logging
|
||||
import nova.image.fake
|
||||
from nova.volume import utils as volume_utils
|
||||
from nova.notifier import test_notifier
|
||||
from nova.openstack.common import importutils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
class UsageInfoTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(UsageInfoTestCase, self).setUp()
|
||||
self.flags(connection_type='fake',
|
||||
stub_network=True,
|
||||
host='fake')
|
||||
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
|
||||
'nova.notifier.test_notifier')
|
||||
self.volume = importutils.import_object(FLAGS.volume_manager)
|
||||
self.user_id = 'fake'
|
||||
self.project_id = 'fake'
|
||||
self.snapshot_id = 'fake'
|
||||
self.volume_size = 0
|
||||
self.context = context.RequestContext(self.user_id, self.project_id)
|
||||
test_notifier.NOTIFICATIONS = []
|
||||
|
||||
def _create_volume(self, params={}):
|
||||
"""Create a test volume"""
|
||||
vol = {}
|
||||
vol['snapshot_id'] = self.snapshot_id
|
||||
vol['user_id'] = self.user_id
|
||||
vol['project_id'] = self.project_id
|
||||
vol['host'] = FLAGS.host
|
||||
vol['availability_zone'] = FLAGS.storage_availability_zone
|
||||
vol['status'] = "creating"
|
||||
vol['attach_status'] = "detached"
|
||||
vol['size'] = self.volume_size
|
||||
vol.update(params)
|
||||
return db.volume_create(self.context, vol)['id']
|
||||
|
||||
def test_notify_usage_exists(self):
|
||||
"""Ensure 'exists' notification generates appropriate usage data."""
|
||||
volume_id = self._create_volume()
|
||||
volume = db.volume_get(self.context, volume_id)
|
||||
volume_utils.notify_usage_exists(self.context, volume)
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
|
||||
msg = test_notifier.NOTIFICATIONS[0]
|
||||
self.assertEquals(msg['priority'], 'INFO')
|
||||
self.assertEquals(msg['event_type'], 'volume.exists')
|
||||
payload = msg['payload']
|
||||
self.assertEquals(payload['tenant_id'], self.project_id)
|
||||
self.assertEquals(payload['user_id'], self.user_id)
|
||||
self.assertEquals(payload['snapshot_id'], self.snapshot_id)
|
||||
self.assertEquals(payload['volume_id'], volume.id)
|
||||
self.assertEquals(payload['size'], self.volume_size)
|
||||
for attr in ('display_name', 'created_at', 'launched_at',
|
||||
'status', 'audit_period_beginning',
|
||||
'audit_period_ending'):
|
||||
self.assertTrue(attr in payload,
|
||||
msg="Key %s not in payload" % attr)
|
||||
db.volume_destroy(context.get_admin_context(), volume['id'])
|
Reference in New Issue
Block a user