Rework collectd plugins for OpenStack
Change-Id: I0c9bd6b0a02a4a402f3d18c2804a0d65defcbac8
diff --git a/collectd/files/plugin/check_openstack_api.py b/collectd/files/plugin/check_openstack_api.py
index bcfea7b..f775208 100644
--- a/collectd/files/plugin/check_openstack_api.py
+++ b/collectd/files/plugin/check_openstack_api.py
@@ -49,6 +49,11 @@
'path': 'healthcheck', 'expect': [200], 'name': 'swift-s3-api'},
}
+ def __init__(self, *args, **kwargs):
+ super(APICheckPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
+
def _service_url(self, endpoint, path):
url = urlparse(endpoint)
u = '%s://%s' % (url.scheme, url.netloc)
@@ -68,24 +73,25 @@
if name not in self.CHECK_MAP:
self.logger.notice(
"No check found for service '%s', skipping it" % name)
- continue
-
- check = self.CHECK_MAP[name]
- url = self._service_url(service['url'], check['path'])
- r = self.raw_get(url, token_required=check.get('auth', False))
-
- if r is None or r.status_code not in check['expect']:
- def _status(ret):
- return 'N/A' if r is None else r.status_code
-
- self.logger.notice(
- "Service %s check failed "
- "(returned '%s' but expected '%s')" % (
- name, _status(r), check['expect'])
- )
- status = self.FAIL
+ status = self.UNKNOWN
+ check = {}
else:
- status = self.OK
+ check = self.CHECK_MAP[name]
+ url = self._service_url(service['url'], check['path'])
+ r = self.raw_get(url, token_required=check.get('auth', False))
+
+ if r is None or r.status_code not in check['expect']:
+ def _status(ret):
+ return 'N/A' if r is None else r.status_code
+
+ self.logger.notice(
+ "Service %s check failed "
+ "(returned '%s' but expected '%s')" % (
+ name, _status(r), check['expect'])
+ )
+ status = self.FAIL
+ else:
+ status = self.OK
yield {
'service': check.get('name', name),
@@ -93,21 +99,15 @@
'region': service['region']
}
- def collect(self):
+ def itermetrics(self):
for item in self.check_api():
- if item['status'] == self.UNKNOWN:
+ if item['status'] != self.UNKNOWN:
# skip if status is UNKNOWN
- continue
-
- value = collectd.Values(
- plugin=PLUGIN_NAME,
- plugin_instance=item['service'],
- type='gauge',
- interval=INTERVAL,
- values=[item['status']],
- meta={'region': item['region']}
- )
- value.dispatch()
+ yield {
+ 'plugin_instance': item['service'],
+ 'values': item['status'],
+ 'meta': {'region': item['region']},
+ }
plugin = APICheckPlugin(collectd, PLUGIN_NAME)
diff --git a/collectd/files/plugin/collectd_base.py b/collectd/files/plugin/collectd_base.py
index e869a97..c59149f 100644
--- a/collectd/files/plugin/collectd_base.py
+++ b/collectd/files/plugin/collectd_base.py
@@ -141,11 +141,12 @@
(self.plugin, type_instance[:24], len(type_instance),
self.MAX_IDENTIFIER_LENGTH))
+ plugin_instance = metric.get('plugin_instance', self.plugin_instance)
v = self.collectd.Values(
plugin=self.plugin,
host=metric.get('hostname', ''),
type=metric.get('type', 'gauge'),
- plugin_instance=self.plugin_instance,
+ plugin_instance=plugin_instance,
type_instance=type_instance,
values=values,
# w/a for https://github.com/collectd/collectd/issues/716
diff --git a/collectd/files/plugin/collectd_openstack.py b/collectd/files/plugin/collectd_openstack.py
index 955d780..7108d04 100644
--- a/collectd/files/plugin/collectd_openstack.py
+++ b/collectd/files/plugin/collectd_openstack.py
@@ -18,7 +18,6 @@
import dateutil.tz
import requests
import simplejson as json
-import traceback
import collectd_base as base
@@ -276,28 +275,6 @@
keystone_url, self.timeout, self.logger,
self.max_retries)
- def read_callback(self):
- """ Wrapper method
-
- This method calls the actual method which performs
- collection.
- """
-
- try:
- self.collect()
- except Exception as e:
- msg = '{}: fail to get metrics: {}: {}'.format(
- self.service_name or self.plugin, e, traceback.format_exc())
- self.logger.error(msg)
-
- def collect(self):
- """ Read metrics and dispatch values
-
- This method should be overriden by the derived classes.
- """
-
- raise 'collect() method needs to be overriden!'
-
def get_objects(self, project, object_name, api_version='',
params='all_tenants=1'):
""" Return a list of OpenStack objects
diff --git a/collectd/files/plugin/hypervisor_stats.py b/collectd/files/plugin/hypervisor_stats.py
index ba6e050..9b61e3c 100644
--- a/collectd/files/plugin/hypervisor_stats.py
+++ b/collectd/files/plugin/hypervisor_stats.py
@@ -34,6 +34,11 @@
'vcpus_used': 'used_vcpus',
}
+ def __init__(self, *args, **kwargs):
+ super(HypervisorStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
+
def config_callback(self, config):
super(HypervisorStatsPlugin, self).config_callback(config)
for node in config.children:
@@ -42,19 +47,7 @@
if 'cpu_ratio' not in self.extra_config:
self.logger.warning('CpuAllocationRatio parameter not set')
- def dispatch_value(self, name, value, meta=None):
- v = collectd.Values(
- plugin=PLUGIN_NAME,
- type='gauge',
- type_instance=name,
- interval=INTERVAL,
- # w/a for https://github.com/collectd/collectd/issues/716
- meta=meta or {'0': True},
- values=[value]
- )
- v.dispatch()
-
- def collect(self):
+ def itermetrics(self):
nova_aggregates = {}
r = self.get('nova', 'os-aggregates')
if not r:
@@ -84,7 +77,11 @@
host = stats['hypervisor_hostname'].split('.')[0]
for k, v in self.VALUE_MAP.iteritems():
m_val = stats.get(k, 0)
- self.dispatch_value(v, m_val, {'host': host})
+ yield {
+ 'type_instance': v,
+ 'values': m_val,
+ 'meta': {'host': host},
+ }
total_stats[v] += m_val
for agg in nova_aggregates.keys():
agg_hosts = nova_aggregates[agg]['hosts']
@@ -95,7 +92,11 @@
m_vcpus_used = stats.get('vcpus_used', 0)
free = (int(self.extra_config['cpu_ratio'] *
m_vcpus)) - m_vcpus_used
- self.dispatch_value('free_vcpus', free, {'host': host})
+ yield {
+ 'type_instance': 'free_vcpus',
+ 'values': free,
+ 'meta': {'host': host},
+ }
total_stats['free_vcpus'] += free
for agg in nova_aggregates.keys():
agg_hosts = nova_aggregates[agg]['hosts']
@@ -122,12 +123,20 @@
agg_total_free_ram,
2)
for k, v in nova_aggregates[agg]['metrics'].iteritems():
- self.dispatch_value('aggregate_{}'.format(k), v,
- {'aggregate': agg,
- 'aggregate_id': agg_id})
+ yield {
+ 'type_instance': 'aggregate_{}'.format(k),
+ 'values': v,
+ 'meta': {
+ 'aggregate': agg,
+ 'aggregate_id': agg_id,
+ }
+ }
# Dispatch the global metrics
for k, v in total_stats.iteritems():
- self.dispatch_value('total_{}'.format(k), v)
+ yield {
+ 'type_instance': 'total_{}'.format(k),
+ 'values': v,
+ }
plugin = HypervisorStatsPlugin(collectd, PLUGIN_NAME)
diff --git a/collectd/files/plugin/openstack_cinder.py b/collectd/files/plugin/openstack_cinder.py
index 9ad209d..373c081 100644
--- a/collectd/files/plugin/openstack_cinder.py
+++ b/collectd/files/plugin/openstack_cinder.py
@@ -15,9 +15,6 @@
#
# Collectd plugin for getting statistics from Cinder
import collectd
-from collections import Counter
-from collections import defaultdict
-import re
import collectd_openstack as openstack
@@ -26,46 +23,18 @@
class CinderStatsPlugin(openstack.CollectdPlugin):
- """ Class to report the statistics on Cinder service.
+ """ Class to report the statistics on Cinder objects.
- state of agents
number of volumes broken down by state
total size of volumes usable and in error state
"""
- states = {'up': 0, 'down': 1, 'disabled': 2}
- cinder_re = re.compile('^cinder-')
+ def __init__(self, *args, **kwargs):
+ super(CinderStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
- def collect(self):
-
- # Get information of the state per service
- # State can be: 'up', 'down' or 'disabled'
- aggregated_workers = defaultdict(Counter)
-
- for worker in self.iter_workers('cinder'):
- host = worker['host'].split('.')[0]
- service = self.cinder_re.sub('', worker['service'])
- state = worker['state']
-
- aggregated_workers[service][state] += 1
- self.dispatch_value('cinder_service', '',
- self.states[state],
- {'host': host,
- 'service': service,
- 'state': state})
-
- for service in aggregated_workers:
- totalw = sum(aggregated_workers[service].values())
-
- for state in self.states:
- prct = (100.0 * aggregated_workers[service][state]) / totalw
- self.dispatch_value('cinder_services_percent', '',
- prct,
- {'state': state, 'service': service})
-
- self.dispatch_value('cinder_services', '',
- aggregated_workers[service][state],
- {'state': state, 'service': service})
+ def itermetrics(self):
volumes_details = self.get_objects_details('cinder', 'volumes')
@@ -78,38 +47,42 @@
status = self.count_objects_group_by(volumes_details,
group_by_func=groupby)
for s, nb in status.iteritems():
- self.dispatch_value('volumes', s, nb)
+ yield {
+ 'plugin_instance': 'volumes',
+ 'type_instance': s,
+ 'values': nb
+ }
sizes = self.count_objects_group_by(volumes_details,
group_by_func=groupby,
count_func=count_size_bytes)
for n, size in sizes.iteritems():
- self.dispatch_value('volumes_size', n, size)
+ yield {
+ 'plugin_instance': 'volumes_size',
+ 'type_instance': n,
+ 'values': size
+ }
snaps_details = self.get_objects_details('cinder', 'snapshots')
status_snaps = self.count_objects_group_by(snaps_details,
group_by_func=groupby)
for s, nb in status_snaps.iteritems():
- self.dispatch_value('snapshots', s, nb)
+ yield {
+ 'plugin_instance': 'snapshots',
+ 'type_instance': s,
+ 'values': nb
+ }
sizes = self.count_objects_group_by(snaps_details,
group_by_func=groupby,
count_func=count_size_bytes)
for n, size in sizes.iteritems():
- self.dispatch_value('snapshots_size', n, size)
+ yield {
+ 'plugin_instance': 'snapshots_size',
+ 'type_instance': n,
+ 'values': size
+ }
- def dispatch_value(self, plugin_instance, name, value, meta=None):
- v = collectd.Values(
- plugin=PLUGIN_NAME, # metric source
- plugin_instance=plugin_instance,
- type='gauge',
- type_instance=name,
- interval=INTERVAL,
- # w/a for https://github.com/collectd/collectd/issues/716
- meta=meta or {'0': True},
- values=[value]
- )
- v.dispatch()
plugin = CinderStatsPlugin(collectd, PLUGIN_NAME)
diff --git a/collectd/files/plugin/openstack_cinder_services.py b/collectd/files/plugin/openstack_cinder_services.py
new file mode 100644
index 0000000..df08f28
--- /dev/null
+++ b/collectd/files/plugin/openstack_cinder_services.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+# Copyright 2017 Mirantis, Inc.
+#
+# 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.
+#
+# Collectd plugin for getting statistics from Cinder
+import collectd
+from collections import Counter
+from collections import defaultdict
+import re
+
+import collectd_openstack as openstack
+
+PLUGIN_NAME = 'cinder'
+INTERVAL = openstack.INTERVAL
+
+
+class CinderServiceStatsPlugin(openstack.CollectdPlugin):
+ """ Class to report the statistics on Cinder services.
+
+ state of workers broken down by state
+ """
+
+ states = {'up': 0, 'down': 1, 'disabled': 2}
+ cinder_re = re.compile('^cinder-')
+
+ def __init__(self, *args, **kwargs):
+ super(CinderServiceStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
+
+ def itermetrics(self):
+
+ # Get information of the state per service
+ # State can be: 'up', 'down' or 'disabled'
+ aggregated_workers = defaultdict(Counter)
+
+ for worker in self.iter_workers('cinder'):
+ host = worker['host'].split('.')[0]
+ service = self.cinder_re.sub('', worker['service'])
+ state = worker['state']
+
+ aggregated_workers[service][state] += 1
+ yield {
+ 'plugin_instance': 'cinder_service',
+ 'values': self.states[state],
+ 'meta': {'host': host, 'service': service, 'state': state},
+ }
+
+ for service in aggregated_workers:
+ totalw = sum(aggregated_workers[service].values())
+
+ for state in self.states:
+ prct = (100.0 * aggregated_workers[service][state]) / totalw
+ yield {
+ 'plugin_instance': 'cinder_services_percent',
+ 'values': prct,
+ 'meta': {'state': state, 'service': service}
+ }
+ yield {
+ 'plugin_instance': 'cinder_services',
+ 'values': aggregated_workers[service][state],
+ 'meta': {'state': state, 'service': service},
+ }
+
+
+plugin = CinderServiceStatsPlugin(collectd, PLUGIN_NAME)
+
+
+def config_callback(conf):
+ plugin.config_callback(conf)
+
+
+def notification_callback(notification):
+ plugin.notification_callback(notification)
+
+
+def read_callback():
+ plugin.conditional_read_callback()
+
+collectd.register_config(config_callback)
+collectd.register_notification(notification_callback)
+collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_glance.py b/collectd/files/plugin/openstack_glance.py
index 1077083..a6b451f 100644
--- a/collectd/files/plugin/openstack_glance.py
+++ b/collectd/files/plugin/openstack_glance.py
@@ -29,7 +29,12 @@
total size of images usable and in error state
"""
- def collect(self):
+ def __init__(self, *args, **kwargs):
+ super(GlanceStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
+
+ def itermetrics(self):
def is_snap(d):
return d.get('properties', {}).get('image_type') == 'snapshot'
@@ -48,8 +53,11 @@
group_by_func=groupby)
for s, nb in status.iteritems():
(name, visibility, status) = s.split('.')
- self.dispatch_value(name, nb, meta={'visibility': visibility,
- 'status': status})
+ yield {
+ 'type_instance': name,
+ 'values': nb,
+ 'meta': {'visibility': visibility, 'status': status}
+ }
# sizes
def count_size_bytes(d):
@@ -67,20 +75,11 @@
count_func=count_size_bytes)
for s, nb in sizes.iteritems():
(name, visibility, status) = s.split('.')
- self.dispatch_value(name, nb, meta={'visibility': visibility,
- 'status': status})
-
- def dispatch_value(self, name, value, meta=None):
- v = collectd.Values(
- plugin=PLUGIN_NAME, # metric source
- type='gauge',
- type_instance=name,
- interval=INTERVAL,
- # w/a for https://github.com/collectd/collectd/issues/716
- meta=meta or {'0': True},
- values=[value]
- )
- v.dispatch()
+ yield {
+ 'type_instance': name,
+ 'values': nb,
+ 'meta': {'visibility': visibility, 'status': status},
+ }
plugin = GlanceStatsPlugin(collectd, PLUGIN_NAME)
diff --git a/collectd/files/plugin/openstack_keystone.py b/collectd/files/plugin/openstack_keystone.py
index c88c6e2..b84fbc6 100644
--- a/collectd/files/plugin/openstack_keystone.py
+++ b/collectd/files/plugin/openstack_keystone.py
@@ -29,7 +29,12 @@
number of roles
"""
- def collect(self):
+ def __init__(self, *args, **kwargs):
+ super(KeystoneStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
+
+ def itermetrics(self):
def groupby(d):
return 'enabled' if d.get('enabled') else 'disabled'
@@ -43,7 +48,11 @@
status = self.count_objects_group_by(tenants_details,
group_by_func=groupby)
for s, nb in status.iteritems():
- self.dispatch_value('tenants', nb, meta={'state': s})
+ yield {
+ 'type_instance': 'tenants',
+ 'values': nb,
+ 'meta': {'state': s},
+ }
# users
r = self.get('keystone', 'users')
@@ -54,7 +63,11 @@
status = self.count_objects_group_by(users_details,
group_by_func=groupby)
for s, nb in status.iteritems():
- self.dispatch_value('users', nb, meta={'state': s})
+ yield {
+ 'type_instance': 'users',
+ 'values': nb,
+ 'meta': {'state': s},
+ }
# roles
r = self.get('keystone', 'OS-KSADM/roles')
@@ -62,19 +75,10 @@
self.logger.warning('Could not find Keystone roles')
return
roles = r.json().get('roles', [])
- self.dispatch_value('roles', len(roles))
-
- def dispatch_value(self, name, value, meta=None):
- v = collectd.Values(
- plugin=PLUGIN_NAME, # metric source
- type='gauge',
- type_instance=name,
- interval=INTERVAL,
- # w/a for https://github.com/collectd/collectd/issues/716
- meta=meta or {'0': True},
- values=[value]
- )
- v.dispatch()
+ yield {
+ 'type_instance': 'roles',
+ 'values': len(roles),
+ }
plugin = KeystoneStatsPlugin(collectd, PLUGIN_NAME)
diff --git a/collectd/files/plugin/openstack_neutron.py b/collectd/files/plugin/openstack_neutron.py
index fdc2005..798f091 100644
--- a/collectd/files/plugin/openstack_neutron.py
+++ b/collectd/files/plugin/openstack_neutron.py
@@ -15,9 +15,6 @@
#
# Collectd plugin for getting resource statistics from Neutron
import collectd
-from collections import Counter
-from collections import defaultdict
-import re
import collectd_openstack as openstack
@@ -26,9 +23,8 @@
class NeutronStatsPlugin(openstack.CollectdPlugin):
- """ Class to report the statistics on Neutron service.
+ """ Class to report the statistics on Neutron objects.
- state of agents
number of networks broken down by status
number of subnets
number of ports broken down by owner and status
@@ -36,11 +32,12 @@
number of floating IP addresses broken down by free/associated
"""
- neutron_re = re.compile('^neutron-')
- agent_re = re.compile('-agent$')
- states = {'up': 0, 'down': 1, 'disabled': 2}
+ def __init__(self, *args, **kwargs):
+ super(NeutronStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
- def collect(self):
+ def itermetrics(self):
def groupby_network(x):
return "networks.%s" % x.get('status', 'unknown').lower()
@@ -67,63 +64,33 @@
status = 'free'
return "floatingips.%s" % status
- # Get information of the state per agent
- # State can be up or down
- aggregated_agents = defaultdict(Counter)
-
- for agent in self.iter_workers('neutron'):
- host = agent['host'].split('.')[0]
- service = self.agent_re.sub(
- '', self.neutron_re.sub('', agent['service']))
- state = agent['state']
-
- aggregated_agents[service][state] += 1
- self.dispatch_value('neutron_agent',
- self.states[state],
- {'host': host,
- 'service': service,
- 'state': state})
-
- for service in aggregated_agents:
- totala = sum(aggregated_agents[service].values())
-
- for state in self.states:
- prct = (100.0 * aggregated_agents[service][state]) / totala
- self.dispatch_value('neutron_agents_percent',
- prct,
- {'service': service, 'state': state})
-
- self.dispatch_value('neutron_agents',
- aggregated_agents[service][state],
- {'service': service, 'state': state})
-
# Networks
networks = self.get_objects('neutron', 'networks', api_version='v2.0')
status = self.count_objects_group_by(networks,
group_by_func=groupby_network)
for s, nb in status.iteritems():
- self.dispatch_value(s, nb)
- self.dispatch_value('networks', len(networks))
+ yield {'type_instance': s, 'values': nb}
+ yield {'type_instance': 'networks', 'values': len(networks)}
# Subnets
subnets = self.get_objects('neutron', 'subnets', api_version='v2.0')
- self.dispatch_value('subnets', len(subnets))
+ yield {'type_instance': 'subnets', 'values': len(subnets)}
# Ports
ports = self.get_objects('neutron', 'ports', api_version='v2.0')
status = self.count_objects_group_by(ports,
group_by_func=groupby_port)
for s, nb in status.iteritems():
- self.dispatch_value(s, nb)
- self.dispatch_value('ports', len(ports))
+ yield {'type_instance': s, 'values': nb}
+ yield {'type_instance': 'ports', 'values': len(ports)}
# Routers
routers = self.get_objects('neutron', 'routers', api_version='v2.0')
status = self.count_objects_group_by(routers,
group_by_func=groupby_router)
for s, nb in status.iteritems():
- self.dispatch_value(s, nb)
- self.dispatch_value('routers', len(routers))
+ yield {'type_instance': s, 'values': nb}
+ yield {'type_instance': 'routers', 'values': len(routers)}
# Floating IP addresses
floatingips = self.get_objects('neutron', 'floatingips',
@@ -131,20 +98,9 @@
status = self.count_objects_group_by(floatingips,
group_by_func=groupby_floating)
for s, nb in status.iteritems():
- self.dispatch_value(s, nb)
- self.dispatch_value('floatingips', len(floatingips))
+ yield {'type_instance': s, 'values': nb}
+ yield {'type_instance': 'floatingips', 'values': len(routers)}
- def dispatch_value(self, name, value, meta=None):
- v = collectd.Values(
- plugin=PLUGIN_NAME, # metric source
- type='gauge',
- type_instance=name,
- interval=INTERVAL,
- # w/a for https://github.com/collectd/collectd/issues/716
- meta=meta or {'0': True},
- values=[value]
- )
- v.dispatch()
plugin = NeutronStatsPlugin(collectd, PLUGIN_NAME)
diff --git a/collectd/files/plugin/openstack_neutron_agents.py b/collectd/files/plugin/openstack_neutron_agents.py
new file mode 100644
index 0000000..6116055
--- /dev/null
+++ b/collectd/files/plugin/openstack_neutron_agents.py
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+# Copyright 2015 Mirantis, Inc.
+#
+# 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.
+#
+# Collectd plugin for getting resource statistics from Neutron
+import collectd
+from collections import Counter
+from collections import defaultdict
+import re
+
+import collectd_openstack as openstack
+
+PLUGIN_NAME = 'neutron'
+INTERVAL = openstack.INTERVAL
+
+
+class NeutronAgentStatsPlugin(openstack.CollectdPlugin):
+ """ Class to report the statistics on Neutron agents.
+
+ state of agents
+ """
+
+ neutron_re = re.compile('^neutron-')
+ agent_re = re.compile('-agent$')
+ states = {'up': 0, 'down': 1, 'disabled': 2}
+
+ def __init__(self, *args, **kwargs):
+ super(NeutronAgentStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
+
+ def itermetrics(self):
+
+ # Get information of the state per agent
+ # State can be up or down
+ aggregated_agents = defaultdict(Counter)
+
+ for agent in self.iter_workers('neutron'):
+ host = agent['host'].split('.')[0]
+ service = self.agent_re.sub(
+ '', self.neutron_re.sub('', agent['service']))
+ state = agent['state']
+
+ aggregated_agents[service][state] += 1
+
+ yield {
+ 'type_instance': 'neutron_agent',
+ 'values': self.states[state],
+ 'meta': {'host': host, 'service': service, 'state': state}
+ }
+
+ for service in aggregated_agents:
+ totala = sum(aggregated_agents[service].values())
+
+ for state in self.states:
+ prct = (100.0 * aggregated_agents[service][state]) / totala
+ yield {
+ 'type_instance': 'neutron_agents_percent',
+ 'values': prct,
+ 'meta': {'service': service, 'state': state},
+ }
+ yield {
+ 'type_instance': 'neutron_agents',
+ 'values': aggregated_agents[service][state],
+ 'meta': {'service': service, 'state': state},
+ }
+
+
+plugin = NeutronAgentStatsPlugin(collectd, PLUGIN_NAME)
+
+
+def config_callback(conf):
+ plugin.config_callback(conf)
+
+
+def notification_callback(notification):
+ plugin.notification_callback(notification)
+
+
+def read_callback():
+ plugin.conditional_read_callback()
+
+collectd.register_config(config_callback)
+collectd.register_notification(notification_callback)
+collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_nova.py b/collectd/files/plugin/openstack_nova.py
index 0cbc157..455e5d1 100644
--- a/collectd/files/plugin/openstack_nova.py
+++ b/collectd/files/plugin/openstack_nova.py
@@ -15,9 +15,6 @@
#
# Collectd plugin for getting statistics from Nova
import collectd
-from collections import Counter
-from collections import defaultdict
-import re
import collectd_openstack as openstack
@@ -25,73 +22,33 @@
INTERVAL = openstack.INTERVAL
-class NovaStatsPlugin(openstack.CollectdPlugin):
- """ Class to report the statistics on Nova service.
+class NovaInstanceStatsPlugin(openstack.CollectdPlugin):
+ """ Class to report the statistics on Nova instances.
- status per service and number of instances broken down by state
+ Number of instances broken down by state
"""
+ def __init__(self, *args, **kwargs):
+ super(NovaInstanceStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
- states = {'up': 0, 'down': 1, 'disabled': 2}
- nova_re = re.compile('^nova-')
-
- def collect(self):
-
- # Get information of the state per service
- # State can be: 'up', 'down' or 'disabled'
- aggregated_workers = defaultdict(Counter)
-
- for worker in self.iter_workers('nova'):
- host = worker['host'].split('.')[0]
- service = self.nova_re.sub('', worker['service'])
- state = worker['state']
-
- aggregated_workers[service][state] += 1
- self.dispatch_value('nova_service', '',
- self.states[state],
- {'host': host,
- 'service': service,
- 'state': state})
-
- for service in set(aggregated_workers.keys()).union(
- ('compute', 'scheduler', 'conductor', 'cert', 'consoleauth')):
-
- totalw = sum(aggregated_workers[service].values())
-
- for state in self.states:
- prct = 0
- if totalw > 0:
- prct = (100.0 * aggregated_workers[service][state]) / totalw
-
- self.dispatch_value('nova_services_percent', '',
- prct,
- {'state': state, 'service': service})
-
- self.dispatch_value('nova_services', '',
- aggregated_workers[service][state],
- {'state': state, 'service': service})
+ def itermetrics(self):
servers_details = self.get_objects_details('nova', 'servers')
def groupby(d):
return d.get('status', 'unknown').lower()
+
status = self.count_objects_group_by(servers_details,
group_by_func=groupby)
for s, nb in status.iteritems():
- self.dispatch_value('instances', s, nb)
+ yield {
+ 'plugin_instance': 'instances',
+ 'values': nb,
+ 'type_instance': s,
+ }
- def dispatch_value(self, plugin_instance, name, value, meta=None):
- v = collectd.Values(
- plugin=PLUGIN_NAME, # metric source
- plugin_instance=plugin_instance,
- type='gauge',
- type_instance=name,
- interval=INTERVAL,
- # w/a for https://github.com/collectd/collectd/issues/716
- meta=meta or {'0': True},
- values=[value]
- )
- v.dispatch()
-plugin = NovaStatsPlugin(collectd, PLUGIN_NAME)
+plugin = NovaInstanceStatsPlugin(collectd, PLUGIN_NAME)
def config_callback(conf):
diff --git a/collectd/files/plugin/openstack_nova_services.py b/collectd/files/plugin/openstack_nova_services.py
new file mode 100644
index 0000000..774c28c
--- /dev/null
+++ b/collectd/files/plugin/openstack_nova_services.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python
+# Copyright 2017 Mirantis, Inc.
+#
+# 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.
+#
+# Collectd plugin for getting statistics from Nova
+import collectd
+from collections import Counter
+from collections import defaultdict
+import re
+
+import collectd_openstack as openstack
+
+PLUGIN_NAME = 'nova'
+INTERVAL = openstack.INTERVAL
+
+
+class NovaServiceStatsPlugin(openstack.CollectdPlugin):
+ """ Class to report the statistics on Nova services.
+
+ status per service broken down by state
+ """
+
+ states = {'up': 0, 'down': 1, 'disabled': 2}
+ nova_re = re.compile('^nova-')
+
+ def __init__(self, *args, **kwargs):
+ super(NovaServiceStatsPlugin, self).__init__(*args, **kwargs)
+ self.plugin = PLUGIN_NAME
+ self.interval = INTERVAL
+
+ def itermetrics(self):
+
+ # Get information of the state per service
+ # State can be: 'up', 'down' or 'disabled'
+ aggregated_workers = defaultdict(Counter)
+
+ for worker in self.iter_workers('nova'):
+ host = worker['host'].split('.')[0]
+ service = self.nova_re.sub('', worker['service'])
+ state = worker['state']
+
+ aggregated_workers[service][state] += 1
+ yield {
+ 'plugin_instance': 'nova_service',
+ 'values': self.states[state],
+ 'meta': {'host': host, 'service': service, 'state': state}
+ }
+
+ for service in set(aggregated_workers.keys()).union(
+ ('compute', 'scheduler', 'conductor', 'cert', 'consoleauth')):
+
+ total = sum(aggregated_workers[service].values())
+
+ for state in self.states:
+ prct = 0
+ if total > 0:
+ prct = (100.0 * aggregated_workers[service][state]) / total
+
+ yield {
+ 'plugin_instance': 'nova_services_percent',
+ 'values': prct,
+ 'meta': {'state': state, 'service': service},
+ }
+ yield {
+ 'plugin_instance': 'nova_services',
+ 'values': aggregated_workers[service][state],
+ 'meta': {'state': state, 'service': service},
+ }
+
+
+plugin = NovaServiceStatsPlugin(collectd, PLUGIN_NAME)
+
+
+def config_callback(conf):
+ plugin.config_callback(conf)
+
+
+def notification_callback(notification):
+ plugin.notification_callback(notification)
+
+
+def read_callback():
+ plugin.conditional_read_callback()
+
+collectd.register_config(config_callback)
+collectd.register_notification(notification_callback)
+collectd.register_read(read_callback, INTERVAL)