Add pollster data cache

Add a dictionary as a data cache for the pollsters,
creating it outside of the loop where they are
invoked and passing it to them. Future changesets will
include changes to the pollsters to put data in the
cache.

blueprint one-meter-per-plugin

Change-Id: Ie65526dfe65a8880ad8683b62fae62f8e7f9e69b
Signed-off-by: Doug Hellmann <doug.hellmann@dreamhost.com>
This commit is contained in:
Doug Hellmann 2013-07-02 17:08:49 -04:00
parent 2f1378ebea
commit a10773e413
17 changed files with 52 additions and 33 deletions

View File

@ -37,11 +37,15 @@ class PollingTask(agent.PollingTask):
with self.publish_context as publisher: with self.publish_context as publisher:
# TODO(yjiang5) passing counters into get_counters to avoid # TODO(yjiang5) passing counters into get_counters to avoid
# polling all counters one by one # polling all counters one by one
cache = {}
for pollster in self.pollsters: for pollster in self.pollsters:
try: try:
LOG.info("Polling pollster %s", pollster.name) LOG.info("Polling pollster %s", pollster.name)
publisher(list(pollster.obj.get_counters( counters = list(pollster.obj.get_counters(
self.manager))) self.manager,
cache,
))
publisher(counters)
except Exception as err: except Exception as err:
LOG.warning('Continue after error from %s: %s', LOG.warning('Continue after error from %s: %s',
pollster.name, err) pollster.name, err)

View File

@ -37,12 +37,15 @@ class PollingTask(agent.PollingTask):
if getattr(instance, 'OS-EXT-STS:vm_state', None) != 'error': if getattr(instance, 'OS-EXT-STS:vm_state', None) != 'error':
# TODO(yjiang5) passing counters to get_counters to avoid # TODO(yjiang5) passing counters to get_counters to avoid
# polling all counters one by one # polling all counters one by one
cache = {}
for pollster in self.pollsters: for pollster in self.pollsters:
try: try:
LOG.info("Polling pollster %s", pollster.name) LOG.info("Polling pollster %s", pollster.name)
publisher(list(pollster.obj.get_counters( publisher(list(pollster.obj.get_counters(
self.manager, self.manager,
instance))) cache,
instance,
)))
except Exception as err: except Exception as err:
LOG.warning('Continue after error from %s: %s', LOG.warning('Continue after error from %s: %s',
pollster.name, err) pollster.name, err)

View File

@ -55,12 +55,14 @@ class DeletedInstanceStatsGatherer(object):
self.mgr = extensions self.mgr = extensions
self.inspector = inspector.get_hypervisor_inspector() self.inspector = inspector.get_hypervisor_inspector()
def _get_counters_from_plugin(self, ext, instance, *args, **kwds): def _get_counters_from_plugin(self, ext, cache, instance, *args, **kwds):
"""Used with the extenaion manager map() method.""" """Used with the extenaion manager map() method."""
return ext.obj.get_counters(self, instance) return ext.obj.get_counters(self, cache, instance)
def __call__(self, instance): def __call__(self, instance):
cache = {}
counters = self.mgr.map(self._get_counters_from_plugin, counters = self.mgr.map(self._get_counters_from_plugin,
cache=cache,
instance=instance, instance=instance,
) )
# counters is a list of lists, so flatten it before returning # counters is a list of lists, so flatten it before returning

View File

@ -30,6 +30,10 @@ class ComputePollster(plugin.PollsterBase):
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
@abc.abstractmethod @abc.abstractmethod
def get_counters(self, manager, context): def get_counters(self, manager, cache, instance):
"""Return a sequence of Counter instances from polling the resources. """Return a sequence of Counter instances from polling the resources.
:param manager: The service manager invoking the plugin
:param cache: A dictionary for passing data between plugins
:param instance: The instance to examine
""" """

View File

@ -57,7 +57,7 @@ class InstancePollster(plugin.ComputePollster):
# variable. We don't need such format in future # variable. We don't need such format in future
return ['instance', 'instance:*'] return ['instance', 'instance:*']
def get_counters(self, manager, instance): def get_counters(self, manager, cache, instance):
yield make_counter_from_instance(instance, yield make_counter_from_instance(instance,
name='instance', name='instance',
type=counter.TYPE_GAUGE, type=counter.TYPE_GAUGE,
@ -91,7 +91,7 @@ class DiskIOPollster(plugin.ComputePollster):
'disk.write.requests', 'disk.write.requests',
'disk.write.bytes'] 'disk.write.bytes']
def get_counters(self, manager, instance): def get_counters(self, manager, cache, instance):
instance_name = _instance_name(instance) instance_name = _instance_name(instance)
try: try:
r_bytes = 0 r_bytes = 0
@ -164,7 +164,7 @@ class CPUPollster(plugin.ComputePollster):
def get_counter_names(): def get_counter_names():
return ['cpu', 'cpu_util'] return ['cpu', 'cpu_util']
def get_counters(self, manager, instance): def get_counters(self, manager, cache, instance):
self.LOG.info('checking instance %s', instance.id) self.LOG.info('checking instance %s', instance.id)
instance_name = _instance_name(instance) instance_name = _instance_name(instance)
try: try:
@ -237,7 +237,7 @@ class NetPollster(plugin.ComputePollster):
'network.outgoing.bytes', 'network.outgoing.bytes',
'network.outgoing.packets'] 'network.outgoing.packets']
def get_counters(self, manager, instance): def get_counters(self, manager, cache, instance):
instance_name = _instance_name(instance) instance_name = _instance_name(instance)
self.LOG.info('checking instance %s', instance.id) self.LOG.info('checking instance %s', instance.id)
try: try:

View File

@ -77,7 +77,7 @@ class KwapiPollster(_Base):
def get_counter_names(): def get_counter_names():
return ['energy', 'power'] return ['energy', 'power']
def get_counters(self, manager): def get_counters(self, manager, cache):
"""Returns all counters.""" """Returns all counters."""
for probe in self.iter_probes(manager.keystone): for probe in self.iter_probes(manager.keystone):
yield counter.Counter( yield counter.Counter(

View File

@ -99,7 +99,7 @@ class ImagePollster(_Base):
def get_counter_names(): def get_counter_names():
return ['image', 'image.size'] return ['image', 'image.size']
def get_counters(self, manager): def get_counters(self, manager, cache):
for image in self.iter_images(manager.keystone): for image in self.iter_images(manager.keystone):
yield counter.Counter( yield counter.Counter(
name='image', name='image',

View File

@ -35,7 +35,7 @@ class FloatingIPPollster(plugin.CentralPollster):
def get_counter_names(): def get_counter_names():
return ['ip.floating'] return ['ip.floating']
def get_counters(self, manager): def get_counters(self, manager, cache):
nv = nova_client.Client() nv = nova_client.Client()
for ip in nv.floating_ip_get_all(): for ip in nv.floating_ip_get_all():
self.LOG.info("FLOATING IP USAGE: %s" % ip.ip) self.LOG.info("FLOATING IP USAGE: %s" % ip.ip)

View File

@ -55,7 +55,7 @@ class _Base(plugin.PollsterBase):
def iter_accounts(ksclient): def iter_accounts(ksclient):
"""Iterate over all accounts, yielding (tenant_id, stats) tuples.""" """Iterate over all accounts, yielding (tenant_id, stats) tuples."""
def get_counters(self, manager): def get_counters(self, manager, cache):
for tenant, account in self.iter_accounts(manager.keystone): for tenant, account in self.iter_accounts(manager.keystone):
yield counter.Counter( yield counter.Counter(
name='storage.objects', name='storage.objects',

View File

@ -88,7 +88,13 @@ class PollsterBase(PluginBase):
"""Return a sequence of Counter names supported by the pollster.""" """Return a sequence of Counter names supported by the pollster."""
@abc.abstractmethod @abc.abstractmethod
def get_counters(self, manager, instance): def get_counters(self, manager, cache):
"""Return a sequence of Counter instances from polling the resources. """Return a sequence of Counter instances from polling the resources.
:param manager: The service manager class invoking the plugin.
:param cache: A dictionary to allow pollsters to pass data
between themselves when recomputing it would be
expensive (e.g., asking another service for a
list of objects).
""" """

View File

@ -77,7 +77,7 @@ class TestNovaNotifier(base.TestCase):
}, },
) )
def get_counters(self, manager, instance): def get_counters(self, manager, cache, instance):
self.instances.append((manager, instance)) self.instances.append((manager, instance))
return [self.test_data] return [self.test_data]

View File

@ -52,17 +52,17 @@ class TestPollster:
def get_counter_names(self): def get_counter_names(self):
return [self.test_data.name] return [self.test_data.name]
def get_counters(self, manager, instance=None): def get_counters(self, manager, cache, instance=None):
self.counters.append((manager, instance)) self.counters.append((manager, instance))
return [self.test_data] return [self.test_data]
class TestPollsterException(TestPollster): class TestPollsterException(TestPollster):
def get_counters(self, manager, instance=None): def get_counters(self, manager, cache, instance=None):
# Put an instance parameter here so that it can be used # Put an instance parameter here so that it can be used
# by both central manager and compute manager # by both central manager and compute manager
# In future, we possibly don't need such hack if we # In future, we possibly don't need such hack if we
# combin the get_counters() function again # combine the get_counters() function again
self.counters.append((manager, instance)) self.counters.append((manager, instance))
raise Exception() raise Exception()

View File

@ -56,7 +56,7 @@ class TestInstancePollster(TestPollsterBase):
mgr = manager.AgentManager() mgr = manager.AgentManager()
pollster = pollsters.InstancePollster() pollster = pollsters.InstancePollster()
counters = list(pollster.get_counters(mgr, self.instance)) counters = list(pollster.get_counters(mgr, {}, self.instance))
self.assertEquals(len(counters), 2) self.assertEquals(len(counters), 2)
self.assertEqual(counters[0].name, 'instance') self.assertEqual(counters[0].name, 'instance')
self.assertEqual(counters[1].name, 'instance:m1.small') self.assertEqual(counters[1].name, 'instance:m1.small')
@ -80,7 +80,7 @@ class TestDiskIOPollster(TestPollsterBase):
mgr = manager.AgentManager() mgr = manager.AgentManager()
pollster = pollsters.DiskIOPollster() pollster = pollsters.DiskIOPollster()
counters = list(pollster.get_counters(mgr, self.instance)) counters = list(pollster.get_counters(mgr, {}, self.instance))
assert counters assert counters
self.assertEqual(set([c.name for c in counters]), self.assertEqual(set([c.name for c in counters]),
@ -143,7 +143,7 @@ class TestNetPollster(TestPollsterBase):
mgr = manager.AgentManager() mgr = manager.AgentManager()
pollster = pollsters.NetPollster() pollster = pollsters.NetPollster()
counters = list(pollster.get_counters(mgr, self.instance)) counters = list(pollster.get_counters(mgr, {}, self.instance))
assert counters assert counters
self.assertEqual(set([c.name for c in counters]), self.assertEqual(set([c.name for c in counters]),
set(pollster.get_counter_names())) set(pollster.get_counter_names()))
@ -203,7 +203,7 @@ class TestCPUPollster(TestPollsterBase):
pollster = pollsters.CPUPollster() pollster = pollsters.CPUPollster()
def _verify_cpu_metering(zero, expected_time): def _verify_cpu_metering(zero, expected_time):
counters = list(pollster.get_counters(mgr, self.instance)) counters = list(pollster.get_counters(mgr, {}, self.instance))
self.assertEquals(len(counters), 2) self.assertEquals(len(counters), 2)
self.assertEqual(set([c.name for c in counters]), self.assertEqual(set([c.name for c in counters]),
set(pollster.get_counter_names())) set(pollster.get_counter_names()))

View File

@ -76,13 +76,13 @@ class TestKwapiPollster(base.TestCase):
self.stubs.Set(kwapi._Base, 'get_kwapi_client', self.stubs.Set(kwapi._Base, 'get_kwapi_client',
self.fake_kwapi_get_kwapi_client) self.fake_kwapi_get_kwapi_client)
counters = list(kwapi.KwapiPollster().get_counters(self.manager)) counters = list(kwapi.KwapiPollster().get_counters(self.manager, {}))
self.assertEqual(len(counters), 0) self.assertEqual(len(counters), 0)
def test_kwapi_counter(self): def test_kwapi_counter(self):
self.stubs.Set(kwapi._Base, 'iter_probes', self.fake_kwapi_iter_probes) self.stubs.Set(kwapi._Base, 'iter_probes', self.fake_kwapi_iter_probes)
counters = list(kwapi.KwapiPollster().get_counters(self.manager)) counters = list(kwapi.KwapiPollster().get_counters(self.manager, {}))
self.assertEqual(len(counters), 6) self.assertEqual(len(counters), 6)
energy_counters = [counter for counter in counters energy_counters = [counter for counter in counters
if counter.name == "energy"] if counter.name == "energy"]
@ -104,6 +104,6 @@ class TestKwapiPollster(base.TestCase):
def test_kwapi_counter_list(self): def test_kwapi_counter_list(self):
self.stubs.Set(kwapi._Base, 'iter_probes', self.fake_kwapi_iter_probes) self.stubs.Set(kwapi._Base, 'iter_probes', self.fake_kwapi_iter_probes)
counters = list(kwapi.KwapiPollster().get_counters(self.manager)) counters = list(kwapi.KwapiPollster().get_counters(self.manager, {}))
self.assertEqual(set([c.name for c in counters]), self.assertEqual(set([c.name for c in counters]),
set(kwapi.KwapiPollster().get_counter_names())) set(kwapi.KwapiPollster().get_counter_names()))

View File

@ -140,7 +140,7 @@ class TestImagePollster(base.TestCase):
self.assertEqual(len(images), len(set(image.id for image in images))) self.assertEqual(len(images), len(set(image.id for image in images)))
def test_glance_image_counter(self): def test_glance_image_counter(self):
counters = list(glance.ImagePollster().get_counters(self.manager)) counters = list(glance.ImagePollster().get_counters(self.manager, {}))
self.assertEqual(len(counters), 6) self.assertEqual(len(counters), 6)
for counter in [c for c in counters if c.name == 'image']: for counter in [c for c in counters if c.name == 'image']:
self.assertEqual(counter.volume, 1) self.assertEqual(counter.volume, 1)
@ -150,6 +150,6 @@ class TestImagePollster(base.TestCase):
counters))) counters)))
def test_get_counter_names(self): def test_get_counter_names(self):
counters = list(glance.ImagePollster().get_counters(self.manager)) counters = list(glance.ImagePollster().get_counters(self.manager, {}))
self.assertEqual(set([c.name for c in counters]), self.assertEqual(set([c.name for c in counters]),
set(glance.ImagePollster().get_counter_names())) set(glance.ImagePollster().get_counter_names()))

View File

@ -65,7 +65,7 @@ class TestFloatingIPPollster(base.TestCase):
# assert False, 'Should have seen an error' # assert False, 'Should have seen an error'
def test_get_counters_not_empty(self): def test_get_counters_not_empty(self):
counters = list(self.pollster.get_counters(self.manager)) counters = list(self.pollster.get_counters(self.manager, {}))
self.assertEqual(len(counters), 3) self.assertEqual(len(counters), 3)
# It's necessary to verify all the attributes extracted by Nova # It's necessary to verify all the attributes extracted by Nova
# API /os-floating-ips to make sure they're available and correct. # API /os-floating-ips to make sure they're available and correct.
@ -82,6 +82,6 @@ class TestFloatingIPPollster(base.TestCase):
self.assertEqual(counters[2].resource_metadata["pool"], "public") self.assertEqual(counters[2].resource_metadata["pool"], "public")
def test_get_counter_names(self): def test_get_counter_names(self):
counters = list(self.pollster.get_counters(self.manager)) counters = list(self.pollster.get_counters(self.manager, {}))
self.assertEqual(set([c.name for c in counters]), self.assertEqual(set([c.name for c in counters]),
set(self.pollster.get_counter_names())) set(self.pollster.get_counter_names()))

View File

@ -77,18 +77,18 @@ class TestSwiftPollster(base.TestCase):
def test_objectstore_metering(self): def test_objectstore_metering(self):
self.stubs.Set(swift.SwiftPollster, 'iter_accounts', self.stubs.Set(swift.SwiftPollster, 'iter_accounts',
self.fake_iter_accounts) self.fake_iter_accounts)
counters = list(self.pollster.get_counters(self.manager)) counters = list(self.pollster.get_counters(self.manager, {}))
self.assertEqual(len(counters), 6) self.assertEqual(len(counters), 6)
def test_objectstore_get_counter_names(self): def test_objectstore_get_counter_names(self):
self.stubs.Set(swift.SwiftPollster, 'iter_accounts', self.stubs.Set(swift.SwiftPollster, 'iter_accounts',
self.fake_iter_accounts) self.fake_iter_accounts)
counters = list(self.pollster.get_counters(self.manager)) counters = list(self.pollster.get_counters(self.manager, {}))
self.assertEqual(set([c.name for c in counters]), self.assertEqual(set([c.name for c in counters]),
set(self.pollster.get_counter_names())) set(self.pollster.get_counter_names()))
def test_objectstore_endpoint_notfound(self): def test_objectstore_endpoint_notfound(self):
self.stubs.Set(self.manager.keystone.service_catalog, 'url_for', self.stubs.Set(self.manager.keystone.service_catalog, 'url_for',
self.fake_ks_service_catalog_url_for) self.fake_ks_service_catalog_url_for)
counters = list(self.pollster.get_counters(self.manager)) counters = list(self.pollster.get_counters(self.manager, {}))
self.assertEqual(len(counters), 0) self.assertEqual(len(counters), 0)