diff options
-rw-r--r-- | nova/compute/manager.py | 56 | ||||
-rw-r--r-- | nova/db/api.py | 9 | ||||
-rw-r--r-- | nova/db/sqlalchemy/api.py | 16 | ||||
-rw-r--r-- | nova/db/sqlalchemy/migrate_repo/versions/121_add_indexes_to_bw_usage_cache.py | 19 | ||||
-rw-r--r-- | nova/db/sqlalchemy/migrate_repo/versions/134_add_counters_to_bw_usage_cache.py | 60 | ||||
-rw-r--r-- | nova/db/sqlalchemy/models.py | 2 | ||||
-rw-r--r-- | nova/tests/test_db_api.py | 15 | ||||
-rw-r--r-- | nova/tests/test_xenapi.py | 88 | ||||
-rw-r--r-- | nova/virt/driver.py | 4 | ||||
-rw-r--r-- | nova/virt/fake.py | 8 | ||||
-rw-r--r-- | nova/virt/xenapi/driver.py | 28 | ||||
-rw-r--r-- | nova/virt/xenapi/vm_utils.py | 9 | ||||
-rw-r--r-- | nova/virt/xenapi/vmops.py | 41 | ||||
-rwxr-xr-x | plugins/xenserver/xenapi/etc/xapi.d/plugins/bandwidth | 51 |
14 files changed, 330 insertions, 76 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 4d88e2772..0f6653c66 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -2525,9 +2525,8 @@ class ComputeManager(manager.SchedulerDependentManager): time.time() - start_time)) @manager.periodic_task - def _poll_bandwidth_usage(self, context, start_time=None, stop_time=None): - if not start_time: - start_time = utils.last_completed_audit_period()[1] + def _poll_bandwidth_usage(self, context): + prev_time, start_time = utils.last_completed_audit_period() curr_time = time.time() if (curr_time - self._last_bw_usage_poll > @@ -2537,8 +2536,7 @@ class ComputeManager(manager.SchedulerDependentManager): instances = self.db.instance_get_all_by_host(context, self.host) try: - bw_usage = self.driver.get_all_bw_usage(instances, start_time, - stop_time) + bw_counters = self.driver.get_all_bw_counters(instances) except NotImplementedError: # NOTE(mdragon): Not all hypervisors have bandwidth polling # implemented yet. If they don't it doesn't break anything, @@ -2546,12 +2544,52 @@ class ComputeManager(manager.SchedulerDependentManager): return refreshed = timeutils.utcnow() - for usage in bw_usage: + for bw_ctr in bw_counters: + # Allow switching of greenthreads between queries. + greenthread.sleep(0) + bw_in = 0 + bw_out = 0 + last_ctr_in = None + last_ctr_out = None + usage = self.db.bw_usage_get(context, + bw_ctr['uuid'], + start_time, + bw_ctr['mac_address']) + if usage: + bw_in = usage['bw_in'] + bw_out = usage['bw_out'] + last_ctr_in = usage['last_ctr_in'] + last_ctr_out = usage['last_ctr_out'] + else: + usage = self.db.bw_usage_get(context, + bw_ctr['uuid'], + prev_time, + bw_ctr['mac_address']) + last_ctr_in = usage['last_ctr_in'] + last_ctr_out = usage['last_ctr_out'] + + if last_ctr_in is not None: + if bw_ctr['bw_in'] < last_ctr_in: + # counter rollover + bw_in += bw_ctr['bw_in'] + else: + bw_in += (bw_ctr['bw_in'] - last_ctr_in) + + if last_ctr_out is not None: + if bw_ctr['bw_out'] < last_ctr_out: + # counter rollover + bw_out += bw_ctr['bw_out'] + else: + bw_out += (bw_ctr['bw_out'] - last_ctr_out) + self.db.bw_usage_update(context, - usage['uuid'], - usage['mac_address'], + bw_ctr['uuid'], + bw_ctr['mac_address'], start_time, - usage['bw_in'], usage['bw_out'], + bw_in, + bw_out, + bw_ctr['bw_in'], + bw_ctr['bw_out'], last_refreshed=refreshed) @manager.periodic_task diff --git a/nova/db/api.py b/nova/db/api.py index cb651793e..4d91c5db9 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -1543,18 +1543,23 @@ def agent_build_update(context, agent_build_id, values): #################### +def bw_usage_get(context, uuid, start_period, mac): + """Return bw usage for instance and mac in a given audit period.""" + return IMPL.bw_usage_get(context, uuid, start_period, mac) + + def bw_usage_get_by_uuids(context, uuids, start_period): """Return bw usages for instance(s) in a given audit period.""" return IMPL.bw_usage_get_by_uuids(context, uuids, start_period) def bw_usage_update(context, uuid, mac, start_period, bw_in, bw_out, - last_refreshed=None): + last_ctr_in, last_ctr_out, last_refreshed=None): """Update cached bandwidth usage for an instance's network based on mac address. Creates new record if needed. """ return IMPL.bw_usage_update(context, uuid, mac, start_period, bw_in, - bw_out, last_refreshed=last_refreshed) + bw_out, last_ctr_in, last_ctr_out, last_refreshed=last_refreshed) #################### diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 3798cade8..10619c9ed 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -4303,6 +4303,15 @@ def agent_build_update(context, agent_build_id, values): #################### @require_context +def bw_usage_get(context, uuid, start_period, mac): + return model_query(context, models.BandwidthUsage, read_deleted="yes").\ + filter_by(start_period=start_period).\ + filter_by(uuid=uuid).\ + filter_by(mac=mac).\ + first() + + +@require_context def bw_usage_get_by_uuids(context, uuids, start_period): return model_query(context, models.BandwidthUsage, read_deleted="yes").\ filter(models.BandwidthUsage.uuid.in_(uuids)).\ @@ -4312,7 +4321,8 @@ def bw_usage_get_by_uuids(context, uuids, start_period): @require_context def bw_usage_update(context, uuid, mac, start_period, bw_in, bw_out, - last_refreshed=None, session=None): + last_ctr_in, last_ctr_out, last_refreshed=None, + session=None): if not session: session = get_session() @@ -4324,6 +4334,8 @@ def bw_usage_update(context, uuid, mac, start_period, bw_in, bw_out, # records. Fall back to creation when no rows are updated. with session.begin(): values = {'last_refreshed': last_refreshed, + 'last_ctr_in': last_ctr_in, + 'last_ctr_out': last_ctr_out, 'bw_in': bw_in, 'bw_out': bw_out} rows = model_query(context, models.BandwidthUsage, @@ -4342,6 +4354,8 @@ def bw_usage_update(context, uuid, mac, start_period, bw_in, bw_out, bwusage.last_refreshed = last_refreshed bwusage.bw_in = bw_in bwusage.bw_out = bw_out + bwusage.last_ctr_in = last_ctr_in + bwusage.last_ctr_out = last_ctr_out bwusage.save(session=session) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/121_add_indexes_to_bw_usage_cache.py b/nova/db/sqlalchemy/migrate_repo/versions/121_add_indexes_to_bw_usage_cache.py index fcbe49061..1345e5396 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/121_add_indexes_to_bw_usage_cache.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/121_add_indexes_to_bw_usage_cache.py @@ -16,7 +16,7 @@ # under the License. from sqlalchemy import Index, MetaData, Table -from sqlalchemy.exc import IntegrityError +from sqlalchemy.exc import IntegrityError, OperationalError def upgrade(migrate_engine): @@ -41,4 +41,19 @@ def downgrade(migrate_engine): t = Table('bw_usage_cache', meta, autoload=True) i = Index('bw_usage_cache_uuid_start_period_idx', t.c.uuid, t.c.start_period) - i.drop(migrate_engine) + if migrate_engine.url.get_dialect().name.startswith('sqlite'): + try: + i.drop(migrate_engine) + except OperationalError: + # Sqlite is very broken for any kind of table modification. + # adding columns creates a new table, then copies the data, + # and looses the indexes. + # Thus later migrations that add columns will cause the + # earlier migration's downgrade unittests to fail on + # dropping indexes. + # Honestly testing migrations on sqlite is not really a very + # valid test (because of above facts), but that is for + # another day. (mdragon) + pass + else: + i.drop(migrate_engine) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/134_add_counters_to_bw_usage_cache.py b/nova/db/sqlalchemy/migrate_repo/versions/134_add_counters_to_bw_usage_cache.py new file mode 100644 index 000000000..985149e91 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/134_add_counters_to_bw_usage_cache.py @@ -0,0 +1,60 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack LLC. +# +# 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. + +from sqlalchemy import Boolean, Column, DateTime, BigInteger +from sqlalchemy import MetaData, Integer, String, Table + +from nova.openstack.common import log as logging + +LOG = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + # add column: + bw_usage_cache = Table('bw_usage_cache', meta, autoload=True) + last_ctr_in = Column('last_ctr_in', BigInteger()) + last_ctr_out = Column('last_ctr_out', BigInteger()) + + bw_usage_cache.create_column(last_ctr_in) + bw_usage_cache.create_column(last_ctr_out) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + # drop column: + bw_usage_cache = Table('bw_usage_cache', meta, + Column('created_at', DateTime(timezone=False)), + Column('updated_at', DateTime(timezone=False)), + Column('deleted_at', DateTime(timezone=False)), + Column('deleted', Boolean(create_constraint=True, name=None)), + Column('id', Integer(), primary_key=True, nullable=False), + Column('mac', String(255)), + Column('uuid', String(36)), + Column('start_period', DateTime(timezone=False), nullable=False), + Column('last_refreshed', DateTime(timezone=False)), + Column('bw_in', BigInteger()), + Column('bw_out', BigInteger()), + Column('last_ctr_in', BigInteger()), + Column('last_ctr_out', BigInteger()), + extend_existing=True) + + bw_usage_cache.drop_column('last_ctr_in') + bw_usage_cache.drop_column('last_ctr_out') diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 26981114b..0e960940d 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -937,6 +937,8 @@ class BandwidthUsage(BASE, NovaBase): last_refreshed = Column(DateTime) bw_in = Column(BigInteger) bw_out = Column(BigInteger) + last_ctr_in = Column(BigInteger) + last_ctr_out = Column(BigInteger) class S3Image(BASE, NovaBase): diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index e434faaad..eb0b8bed8 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -478,18 +478,24 @@ class DbApiTestCase(test.TestCase): 'start_period': start_period, 'bw_in': 100, 'bw_out': 200, + 'last_ctr_in': 12345, + 'last_ctr_out': 67890, 'last_refreshed': now}, {'uuid': 'fake_uuid2', 'mac': 'fake_mac2', 'start_period': start_period, 'bw_in': 200, 'bw_out': 300, + 'last_ctr_in': 22345, + 'last_ctr_out': 77890, 'last_refreshed': now}, {'uuid': 'fake_uuid3', 'mac': 'fake_mac3', 'start_period': start_period, 'bw_in': 400, 'bw_out': 500, + 'last_ctr_in': 32345, + 'last_ctr_out': 87890, 'last_refreshed': uuid3_refreshed}] def _compare(bw_usage, expected): @@ -504,18 +510,19 @@ class DbApiTestCase(test.TestCase): # Add 3 entries db.bw_usage_update(ctxt, 'fake_uuid1', 'fake_mac1', start_period, - 100, 200) + 100, 200, 12345, 67890) db.bw_usage_update(ctxt, 'fake_uuid2', 'fake_mac2', start_period, - 100, 200) + 100, 200, 42, 42) # Test explicit refreshed time db.bw_usage_update(ctxt, 'fake_uuid3', 'fake_mac3', start_period, - 400, 500, last_refreshed=uuid3_refreshed) + 400, 500, 32345, 87890, + last_refreshed=uuid3_refreshed) # Update 2nd entry db.bw_usage_update(ctxt, 'fake_uuid2', 'fake_mac2', start_period, - 200, 300) + 200, 300, 22345, 77890) bw_usages = db.bw_usage_get_by_uuids(ctxt, ['fake_uuid1', 'fake_uuid2', 'fake_uuid3'], start_period) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index b543f3e0f..18f8f2ea7 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -1442,11 +1442,23 @@ class XenAPIGenerateLocal(stubs.XenAPITestBase): self.assertCalled(instance) -class XenAPIBWUsageTestCase(stubs.XenAPITestBase): +class XenAPIBWCountersTestCase(stubs.XenAPITestBase): + FAKE_VMS = {'test1:ref': dict(name_label='test1', + other_config=dict(nova_uuid='hash'), + domid='12', + _vifmap={'0': "a:b:c:d...", + '1': "e:f:12:q..."}), + 'test2:ref': dict(name_label='test2', + other_config=dict(nova_uuid='hash'), + domid='42', + _vifmap={'0': "a:3:c:d...", + '1': "e:f:42:q..."}), + } + def setUp(self): - super(XenAPIBWUsageTestCase, self).setUp() - self.stubs.Set(vm_utils, 'compile_metrics', - XenAPIBWUsageTestCase._fake_compile_metrics) + super(XenAPIBWCountersTestCase, self).setUp() + self.stubs.Set(vm_utils, 'list_vms', + XenAPIBWCountersTestCase._fake_list_vms) self.flags(xenapi_connection_url='test_url', xenapi_connection_password='test_pass', firewall_driver='nova.virt.xenapi.firewall.' @@ -1454,21 +1466,75 @@ class XenAPIBWUsageTestCase(stubs.XenAPITestBase): stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) self.conn = xenapi_conn.XenAPIDriver(False) + def _fake_get_vif_device_map(vm_rec): + return vm_rec['_vifmap'] + + self.stubs.Set(self.conn._vmops, "_get_vif_device_map", + _fake_get_vif_device_map) + @classmethod - def _fake_compile_metrics(cls, start_time, stop_time=None): - raise exception.CouldNotFetchMetrics() + def _fake_list_vms(cls, session): + return cls.FAKE_VMS.iteritems() - def test_get_all_bw_usage_in_failure_case(self): - """Test that get_all_bw_usage returns an empty list when metrics - compilation failed. c.f. bug #910045. + @classmethod + def _fake_fetch_bandwidth_mt(cls, session): + return {} + + @classmethod + def _fake_fetch_bandwidth(cls, session): + return {'42': + {'0': {'bw_in': 21024, 'bw_out': 22048}, + '1': {'bw_in': 231337, 'bw_out': 221212121}}, + '12': + {'0': {'bw_in': 1024, 'bw_out': 2048}, + '1': {'bw_in': 31337, 'bw_out': 21212121}}, + } + + def test_get_all_bw_counters(self): + class testinstance(object): + def __init__(self, name, uuid): + self.name = name + self.uuid = uuid + + self.stubs.Set(vm_utils, 'fetch_bandwidth', + XenAPIBWCountersTestCase._fake_fetch_bandwidth) + result = self.conn.get_all_bw_counters([testinstance( + name='test1', + uuid='1-2-3'), + testinstance( + name='test2', + uuid='4-5-6')]) + self.assertEqual(len(result), 4) + self.assertIn(dict(uuid='1-2-3', + mac_address="a:b:c:d...", + bw_in=1024, + bw_out=2048), result) + self.assertIn(dict(uuid='1-2-3', + mac_address="e:f:12:q...", + bw_in=31337, + bw_out=21212121), result) + + self.assertIn(dict(uuid='4-5-6', + mac_address="a:3:c:d...", + bw_in=21024, + bw_out=22048), result) + self.assertIn(dict(uuid='4-5-6', + mac_address="e:f:42:q...", + bw_in=231337, + bw_out=221212121), result) + + def test_get_all_bw_counters_in_failure_case(self): + """Test that get_all_bw_conters returns an empty list when + no data returned from Xenserver. c.f. bug #910045. """ class testinstance(object): def __init__(self): self.name = "instance-0001" self.uuid = "1-2-3-4-5" - result = self.conn.get_all_bw_usage([testinstance()], - timeutils.utcnow()) + self.stubs.Set(vm_utils, 'fetch_bandwidth', + XenAPIBWCountersTestCase._fake_fetch_bandwidth_mt) + result = self.conn.get_all_bw_counters([testinstance()]) self.assertEqual(result, []) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 41df132fc..d741524b0 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -221,8 +221,8 @@ class ComputeDriver(object): # TODO(Vek): Need to pass context in for access to auth_token raise NotImplementedError() - def get_all_bw_usage(self, instances, start_time, stop_time=None): - """Return bandwidth usage info for each interface on each + def get_all_bw_counters(self, instances): + """Return bandwidth usage counters for each interface on each running VM""" raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index a6476f9d9..959ab174c 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -186,11 +186,11 @@ class FakeDriver(driver.ComputeDriver): def get_diagnostics(self, instance_name): return 'FAKE_DIAGNOSTICS' - def get_all_bw_usage(self, instances, start_time, stop_time=None): - """Return bandwidth usage info for each interface on each + def get_all_bw_counters(self, instances): + """Return bandwidth usage counters for each interface on each running VM""" - bwusage = [] - return bwusage + bw = [] + return bw def block_stats(self, instance_name, disk_id): return [0L, 0L, 0L, 0L, None] diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py index 3425c64f8..ad2d64a38 100644 --- a/nova/virt/xenapi/driver.py +++ b/nova/virt/xenapi/driver.py @@ -298,35 +298,27 @@ class XenAPIDriver(driver.ComputeDriver): """Return data about VM diagnostics""" return self._vmops.get_diagnostics(instance) - def get_all_bw_usage(self, instances, start_time, stop_time=None): - """Return bandwidth usage info for each interface on each + def get_all_bw_counters(self, instances): + """Return bandwidth usage counters for each interface on each running VM""" # we only care about VMs that correspond to a nova-managed # instance: imap = dict([(inst.name, inst.uuid) for inst in instances]) - - bwusage = [] - start_time = time.mktime(start_time.timetuple()) - if stop_time: - stop_time = time.mktime(stop_time.timetuple()) + bwcounters = [] # get a dictionary of instance names. values are dictionaries - # of mac addresses with values that are the bw stats: + # of mac addresses with values that are the bw counters: # e.g. {'instance-001' : { 12:34:56:78:90:12 : {'bw_in': 0, ....}} - iusages = self._vmops.get_all_bw_usage(start_time, stop_time) - for instance_name in iusages: + all_counters = self._vmops.get_all_bw_counters() + for instance_name, counters in all_counters.iteritems(): if instance_name in imap: # yes these are stats for a nova-managed vm # correlate the stats with the nova instance uuid: - iusage = iusages[instance_name] - - for macaddr, usage in iusage.iteritems(): - bwusage.append(dict(mac_address=macaddr, - uuid=imap[instance_name], - bw_in=usage['bw_in'], - bw_out=usage['bw_out'])) - return bwusage + for vif_counter in counters.values(): + vif_counter['uuid'] = imap[instance_name] + bwcounters.append(vif_counter) + return bwcounters def get_console_output(self, instance): """Return snapshot of console""" diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index a9adb4575..2dc358f0f 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -1351,9 +1351,16 @@ def compile_diagnostics(record): return {"Unable to retrieve diagnostics": e} +def fetch_bandwidth(session): + bw = session.call_plugin_serialized('bandwidth', 'fetch_all_bandwidth') + return bw + + def compile_metrics(start_time, stop_time=None): """Compile bandwidth usage, cpu, and disk metrics for all VMs on - this host""" + this host. + Note that some stats, like bandwith, do not seem to be very + accurate in some of the data from XenServer (mdragon). """ start_time = int(start_time) xml = _get_rrd_updates(_get_rrd_server(), start_time) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 52cb9b17b..ad6f0d38c 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -1208,34 +1208,31 @@ class VMOps(object): vm_rec = self._session.call_xenapi("VM.get_record", vm_ref) return vm_utils.compile_diagnostics(vm_rec) - def get_all_bw_usage(self, start_time, stop_time=None): - """Return bandwidth usage info for each interface on each + def _get_vif_device_map(self, vm_rec): + vif_map = {} + for vif in [self._session.call_xenapi("VIF.get_record", vrec) + for vrec in vm_rec['VIFs']]: + vif_map[vif['device']] = vif['MAC'] + return vif_map + + def get_all_bw_counters(self): + """Return running bandwidth counter for each interface on each running VM""" - try: - metrics = vm_utils.compile_metrics(start_time, stop_time) - except exception.CouldNotFetchMetrics: - LOG.exception(_("Could not get bandwidth info.")) - return {} + counters = vm_utils.fetch_bandwidth(self._session) bw = {} - for uuid, data in metrics.iteritems(): - vm_ref = self._session.call_xenapi("VM.get_by_uuid", uuid) - vm_rec = self._session.call_xenapi("VM.get_record", vm_ref) - vif_map = {} - for vif in [self._session.call_xenapi("VIF.get_record", vrec) - for vrec in vm_rec['VIFs']]: - vif_map[vif['device']] = vif['MAC'] + for vm_ref, vm_rec in vm_utils.list_vms(self._session): + vif_map = self._get_vif_device_map(vm_rec) name = vm_rec['name_label'] if 'nova_uuid' not in vm_rec['other_config']: continue + dom = vm_rec.get('domid') + if dom is None or dom not in counters: + continue vifs_bw = bw.setdefault(name, {}) - for key, val in data.iteritems(): - if key.startswith('vif_'): - vname = key.split('_')[1] - vif_bw = vifs_bw.setdefault(vif_map[vname], {}) - if key.endswith('tx'): - vif_bw['bw_out'] = int(val) - if key.endswith('rx'): - vif_bw['bw_in'] = int(val) + for vif_num, vif_data in counters[dom].iteritems(): + mac = vif_map[vif_num] + vif_data['mac_address'] = mac + vifs_bw[mac] = vif_data return bw def get_console_output(self, instance): diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/bandwidth b/plugins/xenserver/xenapi/etc/xapi.d/plugins/bandwidth new file mode 100755 index 000000000..171011a06 --- /dev/null +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/bandwidth @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +# Copyright (c) 2012 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. + +"""Fetch Bandwidth data from VIF network devices.""" + +import os +import shutil + +import utils + +from pluginlib_nova import * +configure_logging('bandwidth') + + +def _read_proc_net(): + devs = [l.strip() for l in open('/proc/net/dev', 'r').readlines()] + #ignore headers + devs = devs[2:] + dlist = [d.split(':', 1) for d in devs if d.startswith('vif')] + devmap = dict() + for name, stats in dlist: + slist = stats.split() + dom, vifnum = name[3:].split('.', 1) + dev = devmap.get(dom, {}) + # Note, we deliberately swap in and out, as instance traffic + # shows up inverted due to going though the bridge. (mdragon) + dev[vifnum] = dict(bw_in=int(slist[0]), bw_out=int(slist[8])) + devmap[dom] = dev + return devmap + + +def fetch_all_bandwidth(session): + return _read_proc_net() + + +if __name__ == '__main__': + utils.register_plugin_calls(fetch_all_bandwidth) |