Implements volume usage metering.
Add volume usage cache tables to record no. of reads, bytes read, no. of write, bytes written to a volume. A periodic task runs in compute manager to query each volume mounted on a compute host and record its usage, this task also send a volume.usage notification contains volume usage statistics Part of blueprint volume-usage-metering Change-Id: I215ce0c94e9ea5a07e18940802c20d1379b8f6d1
This commit is contained in:
@@ -1315,3 +1315,89 @@ class InstanceDestroyConstraints(test.TestCase):
|
||||
ctx, instance['uuid'], constraint)
|
||||
instance = db.instance_get_by_uuid(ctx, instance['uuid'])
|
||||
self.assertFalse(instance['deleted'])
|
||||
|
||||
|
||||
class VolumeUsageDBApiTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(VolumeUsageDBApiTestCase, self).setUp()
|
||||
self.user_id = 'fake'
|
||||
self.project_id = 'fake'
|
||||
self.context = context.RequestContext(self.user_id, self.project_id)
|
||||
|
||||
def test_vol_usage_update_no_totals_update(self):
|
||||
ctxt = context.get_admin_context()
|
||||
now = timeutils.utcnow()
|
||||
timeutils.set_time_override(now)
|
||||
start_time = now - datetime.timedelta(seconds=10)
|
||||
refreshed_time = now - datetime.timedelta(seconds=5)
|
||||
|
||||
expected_vol_usages = [{'volume_id': u'1',
|
||||
'curr_reads': 1000,
|
||||
'curr_read_bytes': 2000,
|
||||
'curr_writes': 3000,
|
||||
'curr_write_bytes': 4000},
|
||||
{'volume_id': u'2',
|
||||
'curr_reads': 100,
|
||||
'curr_read_bytes': 200,
|
||||
'curr_writes': 300,
|
||||
'curr_write_bytes': 400}]
|
||||
|
||||
def _compare(vol_usage, expected):
|
||||
for key, value in expected.items():
|
||||
self.assertEqual(vol_usage[key], value)
|
||||
|
||||
vol_usages = db.vol_get_usage_by_time(ctxt, start_time)
|
||||
self.assertEqual(len(vol_usages), 0)
|
||||
|
||||
vol_usage = db.vol_usage_update(ctxt, 1, rd_req=10, rd_bytes=20,
|
||||
wr_req=30, wr_bytes=40, instance_id=1)
|
||||
vol_usage = db.vol_usage_update(ctxt, 2, rd_req=100, rd_bytes=200,
|
||||
wr_req=300, wr_bytes=400,
|
||||
instance_id=1)
|
||||
vol_usage = db.vol_usage_update(ctxt, 1, rd_req=1000, rd_bytes=2000,
|
||||
wr_req=3000, wr_bytes=4000,
|
||||
instance_id=1,
|
||||
last_refreshed=refreshed_time)
|
||||
|
||||
vol_usages = db.vol_get_usage_by_time(ctxt, start_time)
|
||||
self.assertEqual(len(vol_usages), 2)
|
||||
_compare(vol_usages[0], expected_vol_usages[0])
|
||||
_compare(vol_usages[1], expected_vol_usages[1])
|
||||
timeutils.clear_time_override()
|
||||
|
||||
def test_vol_usage_update_totals_update(self):
|
||||
ctxt = context.get_admin_context()
|
||||
now = timeutils.utcnow()
|
||||
timeutils.set_time_override(now)
|
||||
start_time = now - datetime.timedelta(seconds=10)
|
||||
expected_vol_usages = {'volume_id': u'1',
|
||||
'tot_reads': 600,
|
||||
'tot_read_bytes': 800,
|
||||
'tot_writes': 1000,
|
||||
'tot_write_bytes': 1200,
|
||||
'curr_reads': 0,
|
||||
'curr_read_bytes': 0,
|
||||
'curr_writes': 0,
|
||||
'curr_write_bytes': 0}
|
||||
|
||||
vol_usage = db.vol_usage_update(ctxt, 1, rd_req=100, rd_bytes=200,
|
||||
wr_req=300, wr_bytes=400,
|
||||
instance_id=1)
|
||||
vol_usage = db.vol_usage_update(ctxt, 1, rd_req=200, rd_bytes=300,
|
||||
wr_req=400, wr_bytes=500,
|
||||
instance_id=1,
|
||||
update_totals=True)
|
||||
vol_usage = db.vol_usage_update(ctxt, 1, rd_req=300, rd_bytes=400,
|
||||
wr_req=500, wr_bytes=600,
|
||||
instance_id=1)
|
||||
vol_usage = db.vol_usage_update(ctxt, 1, rd_req=400, rd_bytes=500,
|
||||
wr_req=600, wr_bytes=700,
|
||||
instance_id=1,
|
||||
update_totals=True)
|
||||
|
||||
vol_usages = db.vol_get_usage_by_time(ctxt, start_time)
|
||||
|
||||
self.assertEquals(1, len(vol_usages))
|
||||
for key, value in expected_vol_usages.items():
|
||||
self.assertEqual(vol_usages[0][key], value)
|
||||
timeutils.clear_time_override()
|
||||
|
@@ -4213,6 +4213,56 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
_fake_network_info(self.stubs, 1))
|
||||
|
||||
|
||||
class LibvirtVolumeUsageTestCase(test.TestCase):
|
||||
"""Test for nova.virt.libvirt.libvirt_driver.LibvirtDriver
|
||||
.get_all_volume_usage"""
|
||||
|
||||
def setUp(self):
|
||||
super(LibvirtVolumeUsageTestCase, self).setUp()
|
||||
self.conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
self.c = context.get_admin_context()
|
||||
|
||||
# creating instance
|
||||
inst = {}
|
||||
inst['uuid'] = '875a8070-d0b9-4949-8b31-104d125c9a64'
|
||||
self.ins_ref = db.instance_create(self.c, inst)
|
||||
|
||||
# verify bootable volume device path also
|
||||
self.bdms = [{'volume_id': 1,
|
||||
'device_name': '/dev/vde'},
|
||||
{'volume_id': 2,
|
||||
'device_name': 'vda'}]
|
||||
|
||||
def test_get_all_volume_usage(self):
|
||||
def fake_block_stats(instance_name, disk):
|
||||
return (169L, 688640L, 0L, 0L, -1L)
|
||||
|
||||
self.stubs.Set(self.conn, 'block_stats', fake_block_stats)
|
||||
vol_usage = self.conn.get_all_volume_usage(self.c,
|
||||
[dict(instance=self.ins_ref, instance_bdms=self.bdms)])
|
||||
|
||||
expected_usage = [{'volume': 1,
|
||||
'instance_id': 1,
|
||||
'rd_bytes': 688640L, 'wr_req': 0L,
|
||||
'flush_operations': -1L, 'rd_req': 169L,
|
||||
'wr_bytes': 0L},
|
||||
{'volume': 2,
|
||||
'instance_id': 1,
|
||||
'rd_bytes': 688640L, 'wr_req': 0L,
|
||||
'flush_operations': -1L, 'rd_req': 169L,
|
||||
'wr_bytes': 0L}]
|
||||
self.assertEqual(vol_usage, expected_usage)
|
||||
|
||||
def test_get_all_volume_usage_device_not_found(self):
|
||||
def fake_lookup(instance_name):
|
||||
raise libvirt.libvirtError('invalid path')
|
||||
|
||||
self.stubs.Set(self.conn, '_lookup_by_name', fake_lookup)
|
||||
vol_usage = self.conn.get_all_volume_usage(self.c,
|
||||
[dict(instance=self.ins_ref, instance_bdms=self.bdms)])
|
||||
self.assertEqual(vol_usage, [])
|
||||
|
||||
|
||||
class LibvirtNonblockingTestCase(test.TestCase):
|
||||
"""Test libvirt_nonblocking option"""
|
||||
|
||||
|
Reference in New Issue
Block a user