Merge "Add Docker plugin"
diff --git a/collectd/files/plugin/check_local_endpoint.py b/collectd/files/plugin/check_local_endpoint.py
index d7c2f84..dc77f42 100644
--- a/collectd/files/plugin/check_local_endpoint.py
+++ b/collectd/files/plugin/check_local_endpoint.py
@@ -18,7 +18,7 @@
 import collectd_http_check as http_check
 
 
-NAME = 'check_local_endpoint'
+NAME = 'openstack_check_local_api'
 
 
 class CheckLocalEndpoint(http_check.HTTPCheckPlugin):
@@ -27,7 +27,7 @@
         super(CheckLocalEndpoint, self).__init__(*args, **kwargs)
         self.plugin = NAME
 
-plugin = CheckLocalEndpoint(collectd)
+plugin = CheckLocalEndpoint(collectd, disable_check_metric=True)
 
 
 def config_callback(conf):
diff --git a/collectd/files/plugin/check_openstack_api.py b/collectd/files/plugin/check_openstack_api.py
index f775208..82c4ae8 100644
--- a/collectd/files/plugin/check_openstack_api.py
+++ b/collectd/files/plugin/check_openstack_api.py
@@ -20,7 +20,7 @@
 
 from urlparse import urlparse
 
-PLUGIN_NAME = 'check_openstack_api'
+PLUGIN_NAME = 'openstack_check_api'
 INTERVAL = openstack.INTERVAL
 
 
@@ -104,13 +104,16 @@
             if item['status'] != self.UNKNOWN:
                 # skip if status is UNKNOWN
                 yield {
-                    'plugin_instance': item['service'],
                     'values': item['status'],
-                    'meta': {'region': item['region']},
+                    'meta': {
+                        'region': item['region'],
+                        'service': item['service'],
+                        'discard_hostname': True,
+                    },
                 }
 
 
-plugin = APICheckPlugin(collectd, PLUGIN_NAME)
+plugin = APICheckPlugin(collectd, PLUGIN_NAME, disable_check_metric=True)
 
 
 def config_callback(conf):
diff --git a/collectd/files/plugin/collectd_calico_bird.py b/collectd/files/plugin/collectd_calico_bird.py
new file mode 100644
index 0000000..5b519b8
--- /dev/null
+++ b/collectd/files/plugin/collectd_calico_bird.py
@@ -0,0 +1,153 @@
+#!/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.
+
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
+import re
+import time
+
+import collectd_base as base
+
+NAME = 'calico_bird'
+# Default sampling interval
+INTERVAL = 60
+BIRDCL_BINARY = '/usr/bin/birdcl'
+
+re_memory = re.compile(r"(?P<attribute>.*):\s+"
+                       r"(?P<quantity>\d+)\s"
+                       r"(?P<multiplier>[kMG ])B\s*")
+
+re_protocol = re.compile(r"(?P<name>\S+)\s+"
+                         r"(?P<protocol>\S+)\s+"
+                         r"(?P<table>\S+)\s+"
+                         r"(?P<state>\S+)\s+"
+                         r"(?P<since>\d{2}:\d{2}:\d{2})"
+                         r"(?P<info>.*)")
+
+
+def protocol_metric(line):
+    re_match = re_protocol.match(line)
+    if re_match:
+        if re_match.group("protocol") == "BGP":
+            return gen_metric(
+                'bgp_up', re_match.group('state') == 'up',
+                {
+                    'bird_protocol_instance': re_match.group('name'),
+                }
+            )
+
+
+def memory_metric(line):
+    re_match = re_memory.match(line)
+    if re_match:
+        quantity = int(re_match.group("quantity"))
+        for m in " kMG":
+            if re_match.group("multiplier") == m:
+                break
+            quantity *= 1024
+        mname = 'memory_' + re_match.group(
+            'attribute').lower().replace(' ', '_')
+        return gen_metric(
+            mname, quantity
+        )
+
+
+def gen_metric(name, val, meta={}):
+    ret_metric = {
+        'type_instance': name,
+        'values': val,
+    }
+    if meta:
+        ret_metric['meta'] = meta
+    return ret_metric
+
+
+class CalicoBirdPlugin(base.Base):
+
+    _checks = {
+        'memory': {
+            'cmd_args': ['show', 'memory'],
+            'func': memory_metric,
+        },
+        'protocol': {
+            'cmd_args': ['show', 'protocols'],
+            'func': protocol_metric,
+        },
+    }
+
+    def __init__(self, *args, **kwargs):
+        super(CalicoBirdPlugin, self).__init__(*args, **kwargs)
+        self.plugin = NAME
+        self._socketfiles = {}
+
+    def config_callback(self, config):
+        super(CalicoBirdPlugin, self).config_callback(config)
+        for node in config.children:
+            m = re.search('^ipv(?P<ip_version>[46])_socket$', node.key.lower())
+            if m:
+                self._socketfiles[m.group('ip_version')] = node.values[0]
+
+    def _run_birdcl_command(self, sockf, args):
+        cmd = [
+            BIRDCL_BINARY,
+            '-s',
+            sockf
+        ] + args
+        retcode, out, err = self.execute(cmd, shell=False)
+        if retcode == 0:
+            return out
+        msg = "Failed to execute {} '{}'".format(cmd, err)
+        raise base.CheckException(msg)
+
+    def itermetrics(self):
+        for ipv, sockf in self._socketfiles.items():
+            for lcname, lcheck in self._checks.items():
+                out = self._run_birdcl_command(sockf, lcheck['cmd_args'])
+                for metric in filter(
+                        None,
+                        [lcheck['func'](line) for line in out.split('\n')]
+                ):
+                    if not metric.get('meta', False):
+                        metric['meta'] = {}
+                    metric['meta'].update({'ip_version': ipv})
+                    yield metric
+
+
+plugin = CalicoBirdPlugin(collectd)
+
+
+def init_callback():
+    plugin.restore_sigchld()
+
+
+def config_callback(conf):
+    plugin.config_callback(conf)
+
+
+def read_callback():
+    plugin.read_callback()
+
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+    collectd.info('Sleeping for {}s'.format(INTERVAL))
+    time.sleep(INTERVAL)
+    plugin.read_callback()
+else:
+    collectd.register_init(init_callback)
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/collectd_openstack.py b/collectd/files/plugin/collectd_openstack.py
index a8a72b7..ade9b60 100644
--- a/collectd/files/plugin/collectd_openstack.py
+++ b/collectd/files/plugin/collectd_openstack.py
@@ -209,7 +209,8 @@
         {
           'host': 'node.example.com',
           'service': 'nova-compute',
-          'state': 'up'
+          'state': 'up',
+          'zone': 'az1'
         }
 
         where 'state' can be 'up', 'down' or 'disabled'
@@ -245,11 +246,13 @@
                     data = {'host': val['host'], 'service': val['binary']}
 
                     if service == 'neutron':
+                        data['zone'] = val['availability_zone']
                         if not val['admin_state_up']:
                             data['state'] = 'disabled'
                         else:
                             data['state'] = 'up' if val['alive'] else 'down'
                     else:
+                        data['zone'] = val['zone']
                         if val['status'] == 'disabled':
                             data['state'] = 'disabled'
                         elif val['state'] == 'up' or val['state'] == 'down':
diff --git a/collectd/files/plugin/hypervisor_stats.py b/collectd/files/plugin/hypervisor_stats.py
index 84f735e..5fc3bdb 100644
--- a/collectd/files/plugin/hypervisor_stats.py
+++ b/collectd/files/plugin/hypervisor_stats.py
@@ -21,7 +21,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'hypervisor_stats'
+PLUGIN_NAME = 'openstack_nova'
 INTERVAL = openstack.INTERVAL
 
 
@@ -30,12 +30,18 @@
     VALUE_MAP = {
         'current_workload': 'running_tasks',
         'running_vms': 'running_instances',
-        'local_gb_used': 'used_disk_GB',
-        'free_disk_gb': 'free_disk_GB',
-        'memory_mb_used': 'used_ram_MB',
-        'free_ram_mb': 'free_ram_MB',
+        'local_gb_used': 'used_disk',
+        'free_disk_gb': 'free_disk',
+        'memory_mb_used': 'used_ram',
+        'free_ram_mb': 'free_ram',
         'vcpus_used': 'used_vcpus',
     }
+    UNIT_MAP = {
+        'local_gb_used': 'GB',
+        'free_disk_gb': 'GB',
+        'memory_mb_used': 'MB',
+        'free_ram_mb': 'MB',
+    }
 
     def __init__(self, *args, **kwargs):
         super(HypervisorStatsPlugin, self).__init__(*args, **kwargs)
@@ -50,6 +56,12 @@
         if 'cpu_ratio' not in self.extra_config:
             self.logger.warning('CpuAllocationRatio parameter not set')
 
+    @classmethod
+    def initialize_metrics(self):
+        metrics = {v: 0 for v in self.VALUE_MAP.values()}
+        metrics['free_vcpus'] = 0
+        return metrics
+
     def itermetrics(self):
         nova_aggregates = {}
         r = self.get('nova', 'os-aggregates')
@@ -60,35 +72,34 @@
             for agg in aggregates_list:
                 nova_aggregates[agg['name']] = {
                     'id': agg['id'],
-                    'hosts': agg['hosts'],
-                    'metrics': {'free_vcpus': 0},
+                    'hosts': [h.split('.')[0] for h in agg['hosts']],
+                    'metrics': self.initialize_metrics()
                 }
-                nova_aggregates[agg['name']]['metrics'].update(
-                    {v: 0 for v in self.VALUE_MAP.values()}
-                )
 
         r = self.get('nova', 'os-hypervisors/detail')
         if not r:
             self.logger.warning("Could not get hypervisor statistics")
             return
 
-        total_stats = {v: 0 for v in self.VALUE_MAP.values()}
-        total_stats['free_vcpus'] = 0
+        total_stats = self.initialize_metrics()
         hypervisor_stats = r.json().get('hypervisors', [])
         for stats in hypervisor_stats:
             # remove domain name and keep only the hostname portion
             host = stats['hypervisor_hostname'].split('.')[0]
             for k, v in self.VALUE_MAP.iteritems():
                 m_val = stats.get(k, 0)
+                meta = {'hostname': host}
+                if k in self.UNIT_MAP:
+                    meta['unit'] = self.UNIT_MAP[k]
                 yield {
-                    'type_instance': v,
+                    'plugin_instance': v,
                     'values': m_val,
-                    'meta': {'host': host},
+                    'meta': meta
                 }
                 total_stats[v] += m_val
                 for agg in nova_aggregates.keys():
                     agg_hosts = nova_aggregates[agg]['hosts']
-                    if stats['hypervisor_hostname'] in agg_hosts:
+                    if host in agg_hosts:
                         nova_aggregates[agg]['metrics'][v] += m_val
             if 'cpu_ratio' in self.extra_config:
                 m_vcpus = stats.get('vcpus', 0)
@@ -96,38 +107,35 @@
                 free = (int(self.extra_config['cpu_ratio'] *
                         m_vcpus)) - m_vcpus_used
                 yield {
-                    'type_instance': 'free_vcpus',
+                    'plugin_instance': 'free_vcpus',
                     'values': free,
-                    'meta': {'host': host},
+                    'meta': {'hostname': host},
                 }
                 total_stats['free_vcpus'] += free
                 for agg in nova_aggregates.keys():
                     agg_hosts = nova_aggregates[agg]['hosts']
-                    if stats['hypervisor_hostname'] in agg_hosts:
+                    if host in agg_hosts:
                         free = ((int(self.extra_config['cpu_ratio'] *
                                      m_vcpus)) -
                                 m_vcpus_used)
                         nova_aggregates[agg]['metrics']['free_vcpus'] += free
 
-        # Dispatch the aggregate metrics
+        # Dispatch metrics for every aggregate
         for agg in nova_aggregates.keys():
             agg_id = nova_aggregates[agg]['id']
             agg_total_free_ram = (
-                nova_aggregates[agg]['metrics']['free_ram_MB'] +
-                nova_aggregates[agg]['metrics']['used_ram_MB']
+                nova_aggregates[agg]['metrics']['free_ram'] +
+                nova_aggregates[agg]['metrics']['used_ram']
             )
-            # Only emit metric when value is > 0
-            # If this is not the case, (for instance when no host
-            # in aggregate), this requires the corresponding alarms to
-            # have a 'skip' no_data_policy, so as not to be triggered
+            # Only emit metric when the value is > 0 to avoid division by zero
             if agg_total_free_ram > 0:
                 nova_aggregates[agg]['metrics']['free_ram_percent'] = round(
-                    (100.0 * nova_aggregates[agg]['metrics']['free_ram_MB']) /
+                    (100.0 * nova_aggregates[agg]['metrics']['free_ram']) /
                     agg_total_free_ram,
                     2)
             for k, v in nova_aggregates[agg]['metrics'].iteritems():
                 yield {
-                    'type_instance': 'aggregate_{}'.format(k),
+                    'plugin_instance': 'aggregate_{}'.format(k),
                     'values': v,
                     'meta': {
                         'aggregate': agg,
diff --git a/collectd/files/plugin/openstack_cinder.py b/collectd/files/plugin/openstack_cinder.py
index 96a92c6..fe667a6 100644
--- a/collectd/files/plugin/openstack_cinder.py
+++ b/collectd/files/plugin/openstack_cinder.py
@@ -21,7 +21,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'cinder'
+PLUGIN_NAME = 'openstack_cinder'
 INTERVAL = openstack.INTERVAL
 
 
@@ -55,18 +55,18 @@
         for s, nb in status.iteritems():
             yield {
                 'plugin_instance': 'volumes',
-                'type_instance': s,
-                'values': nb
+                'values': nb,
+                'meta': {'state': s, 'discard_hostname': True}
             }
 
         sizes = self.count_objects_group_by(volumes_details,
                                             group_by_func=groupby,
                                             count_func=count_size_bytes)
-        for n, size in sizes.iteritems():
+        for s, size in sizes.iteritems():
             yield {
                 'plugin_instance': 'volumes_size',
-                'type_instance': n,
-                'values': size
+                'values': size,
+                'meta': {'state': s, 'discard_hostname': True}
             }
 
         snaps_details = self.get_objects('cinderv2', 'snapshots',
@@ -76,8 +76,8 @@
         for s, nb in status_snaps.iteritems():
             yield {
                 'plugin_instance': 'snapshots',
-                'type_instance': s,
-                'values': nb
+                'values': nb,
+                'meta': {'state': s, 'discard_hostname': True}
             }
 
         sizes = self.count_objects_group_by(snaps_details,
@@ -86,8 +86,8 @@
         for n, size in sizes.iteritems():
             yield {
                 'plugin_instance': 'snapshots_size',
-                'type_instance': n,
-                'values': size
+                'values': size,
+                'meta': {'state': s, 'discard_hostname': True}
             }
 
 
diff --git a/collectd/files/plugin/openstack_cinder_services.py b/collectd/files/plugin/openstack_cinder_services.py
index b37dad2..44bb22d 100644
--- a/collectd/files/plugin/openstack_cinder_services.py
+++ b/collectd/files/plugin/openstack_cinder_services.py
@@ -24,7 +24,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'cinder'
+PLUGIN_NAME = 'openstack_cinder'
 INTERVAL = openstack.INTERVAL
 
 
@@ -55,9 +55,10 @@
 
             aggregated_workers[service][state] += 1
             yield {
-                'plugin_instance': 'cinder_service',
+                'plugin_instance': 'service',
                 'values': self.states[state],
-                'meta': {'host': host, 'service': service, 'state': state},
+                'meta': {'hostname': host, 'service': service, 'state': state,
+                         'az': worker['zone']},
             }
 
         for service in aggregated_workers:
@@ -66,14 +67,16 @@
             for state in self.states:
                 prct = (100.0 * aggregated_workers[service][state]) / totalw
                 yield {
-                    'plugin_instance': 'cinder_services_percent',
+                    'plugin_instance': 'services_percent',
                     'values': prct,
-                    'meta': {'state': state, 'service': service}
+                    'meta': {'state': state, 'service': service,
+                             'discard_hostname': True}
                 }
                 yield {
-                    'plugin_instance': 'cinder_services',
+                    'plugin_instance': 'services',
                     'values': aggregated_workers[service][state],
-                    'meta': {'state': state, 'service': service},
+                    'meta': {'state': state, 'service': service,
+                             'discard_hostname': True},
                 }
 
 
diff --git a/collectd/files/plugin/openstack_glance.py b/collectd/files/plugin/openstack_glance.py
index da9c469..90bc9f8 100644
--- a/collectd/files/plugin/openstack_glance.py
+++ b/collectd/files/plugin/openstack_glance.py
@@ -21,7 +21,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'glance'
+PLUGIN_NAME = 'openstack_glance'
 INTERVAL = openstack.INTERVAL
 
 
@@ -57,11 +57,12 @@
         status = self.count_objects_group_by(images_details,
                                              group_by_func=groupby)
         for s, nb in status.iteritems():
-            (name, visibility, status) = s.split('.')
+            (name, visibility, state) = s.split('.')
             yield {
-                'type_instance': name,
+                'plugin_instance': name,
                 'values': nb,
-                'meta': {'visibility': visibility, 'status': status}
+                'meta': {'visibility': visibility, 'state': state,
+                         'discard_hostname': True}
             }
 
         # sizes
@@ -79,11 +80,12 @@
                                             group_by_func=groupby_size,
                                             count_func=count_size_bytes)
         for s, nb in sizes.iteritems():
-            (name, visibility, status) = s.split('.')
+            (name, visibility, state) = s.split('.')
             yield {
-                'type_instance': name,
+                'plugin_instance': name,
                 'values': nb,
-                'meta': {'visibility': visibility, 'status': status},
+                'meta': {'visibility': visibility, 'state': state,
+                         'discard_hostname': True},
             }
 
 plugin = GlanceStatsPlugin(collectd, PLUGIN_NAME, disable_check_metric=True)
diff --git a/collectd/files/plugin/openstack_keystone.py b/collectd/files/plugin/openstack_keystone.py
index 4ad4611..0a0d975 100644
--- a/collectd/files/plugin/openstack_keystone.py
+++ b/collectd/files/plugin/openstack_keystone.py
@@ -21,7 +21,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'keystone'
+PLUGIN_NAME = 'openstack_keystone'
 INTERVAL = openstack.INTERVAL
 
 
@@ -52,9 +52,9 @@
                                              group_by_func=groupby)
         for s, nb in status.iteritems():
             yield {
-                'type_instance': 'tenants',
+                'plugin_instance': 'tenants',
                 'values': nb,
-                'meta': {'state': s},
+                'meta': {'state': s, 'discard_hostname': True},
             }
 
         # users
@@ -67,9 +67,9 @@
                                              group_by_func=groupby)
         for s, nb in status.iteritems():
             yield {
-                'type_instance': 'users',
+                'plugin_instance': 'users',
                 'values': nb,
-                'meta': {'state': s},
+                'meta': {'state': s, 'discard_hostname': True},
             }
 
         # roles
@@ -79,8 +79,9 @@
             return
         roles = r.json().get('roles', [])
         yield {
-            'type_instance': 'roles',
+            'plugin_instance': 'roles',
             'values': len(roles),
+            'meta': {'discard_hostname': True},
         }
 
 plugin = KeystoneStatsPlugin(collectd, PLUGIN_NAME,
diff --git a/collectd/files/plugin/openstack_neutron.py b/collectd/files/plugin/openstack_neutron.py
index f1b72af..1d147c7 100644
--- a/collectd/files/plugin/openstack_neutron.py
+++ b/collectd/files/plugin/openstack_neutron.py
@@ -21,7 +21,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'neutron'
+PLUGIN_NAME = 'openstack_neutron'
 INTERVAL = openstack.INTERVAL
 
 
@@ -43,11 +43,8 @@
 
     def itermetrics(self):
 
-        def groupby_network(x):
-            return "networks.%s" % x.get('status', 'unknown').lower()
-
-        def groupby_router(x):
-            return "routers.%s" % x.get('status', 'unknown').lower()
+        def groupby_status(x):
+            return x.get('status', 'unknown').lower()
 
         def groupby_port(x):
             owner = x.get('device_owner', 'none')
@@ -59,28 +56,34 @@
             else:
                 owner = 'none'
             status = x.get('status', 'unknown').lower()
-            return "ports.%s.%s" % (owner, status)
+            return "%s.%s" % (owner, status)
 
         def groupby_floating(x):
-            if x.get('port_id', None):
-                status = 'associated'
-            else:
-                status = 'free'
-            return "floatingips.%s" % status
+            return 'associated' if x.get('port_id', None) else None
 
         # Networks
         networks = self.get_objects('neutron', 'networks', api_version='v2.0',
                                     params={'fields': ['id', 'status']})
         status = self.count_objects_group_by(networks,
-                                             group_by_func=groupby_network)
+                                             group_by_func=groupby_status)
         for s, nb in status.iteritems():
-            yield {'type_instance': s, 'values': nb}
-        yield {'type_instance': 'networks', 'values': len(networks)}
+            yield {
+                'plugin_instance': 'networks',
+                'values': nb,
+                'meta': {'state': s, 'discard_hostname': True}
+            }
+        yield {
+            'plugin_instance': 'networks',
+            'type_instance': 'total',
+            'values': len(status),
+            'meta': {'discard_hostname': True},
+        }
 
         # Subnets
         subnets = self.get_objects('neutron', 'subnets', api_version='v2.0',
-                                   params={'fields': ['id', 'status']})
-        yield {'type_instance': 'subnets', 'values': len(subnets)}
+                                   params={'fields': ['id']})
+        yield {'plugin_instance': 'subnets', 'values': len(subnets),
+               'meta': {'discard_hostname': True}}
 
         # Ports
         ports = self.get_objects('neutron', 'ports', api_version='v2.0',
@@ -89,17 +92,37 @@
         status = self.count_objects_group_by(ports,
                                              group_by_func=groupby_port)
         for s, nb in status.iteritems():
-            yield {'type_instance': s, 'values': nb}
-        yield {'type_instance': 'ports', 'values': len(ports)}
+            (owner, state) = s.split('.')
+            yield {
+                'plugin_instance': 'ports',
+                'values': nb,
+                'meta': {'state': state, 'owner': owner,
+                         'discard_hostname': True}
+            }
+        yield {
+            'plugin_instance': 'ports',
+            'type_instance': 'total',
+            'values': len(ports),
+            'meta': {'discard_hostname': True},
+        }
 
         # Routers
         routers = self.get_objects('neutron', 'routers', api_version='v2.0',
                                    params={'fields': ['id', 'status']})
         status = self.count_objects_group_by(routers,
-                                             group_by_func=groupby_router)
+                                             group_by_func=groupby_status)
         for s, nb in status.iteritems():
-            yield {'type_instance': s, 'values': nb}
-        yield {'type_instance': 'routers', 'values': len(routers)}
+            yield {
+                'plugin_instance': 'routers',
+                'values': nb,
+                'meta': {'state': s, 'discard_hostname': True}
+            }
+        yield {
+            'plugin_instance': 'routers',
+            'type_instance': 'total',
+            'values': len(routers),
+            'meta': {'discard_hostname': True},
+        }
 
         # Floating IP addresses
         floatingips = self.get_objects('neutron', 'floatingips',
@@ -109,8 +132,17 @@
         status = self.count_objects_group_by(floatingips,
                                              group_by_func=groupby_floating)
         for s, nb in status.iteritems():
-            yield {'type_instance': s, 'values': nb}
-        yield {'type_instance': 'floatingips', 'values': len(routers)}
+            yield {
+                'plugin_instance': 'floatingips',
+                'values': nb,
+                'meta': {'state': s, 'discard_hostname': True}
+            }
+        yield {
+            'plugin_instance': 'floatingips',
+            'type_instance': 'total',
+            'values': len(floatingips),
+            'meta': {'discard_hostname': True},
+        }
 
 
 plugin = NeutronStatsPlugin(collectd, PLUGIN_NAME, disable_check_metric=True)
diff --git a/collectd/files/plugin/openstack_neutron_agents.py b/collectd/files/plugin/openstack_neutron_agents.py
index 0f060a3..fd4b80c 100644
--- a/collectd/files/plugin/openstack_neutron_agents.py
+++ b/collectd/files/plugin/openstack_neutron_agents.py
@@ -24,7 +24,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'neutron'
+PLUGIN_NAME = 'openstack_neutron'
 INTERVAL = openstack.INTERVAL
 
 
@@ -44,23 +44,27 @@
         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'):
+            az = agent['zone']
             host = agent['host'].split('.')[0]
             service = self.agent_re.sub(
                 '', self.neutron_re.sub('', agent['service']))
             state = agent['state']
 
             aggregated_agents[service][state] += 1
+            meta = {'hostname': host, 'service': service, 'state': state}
+            if az:
+                # AZ field is only set for DHCP and L3 agents
+                meta['az'] = az
 
             yield {
-                'type_instance': 'neutron_agent',
+                'plugin_instance': 'agent',
                 'values': self.states[state],
-                'meta': {'host': host, 'service': service, 'state': state}
+                'meta': meta,
             }
 
         for service in aggregated_agents:
@@ -69,14 +73,16 @@
             for state in self.states:
                 prct = (100.0 * aggregated_agents[service][state]) / totala
                 yield {
-                    'type_instance': 'neutron_agents_percent',
+                    'plugin_instance': 'agents_percent',
                     'values': prct,
-                    'meta': {'service': service, 'state': state},
+                    'meta': {'service': service, 'state': state,
+                             'discard_hostname': True},
                 }
                 yield {
-                    'type_instance': 'neutron_agents',
+                    'plugin_instance': 'agents',
                     'values': aggregated_agents[service][state],
-                    'meta': {'service': service, 'state': state},
+                    'meta': {'service': service, 'state': state,
+                             'discard_hostname': True},
                 }
 
 
diff --git a/collectd/files/plugin/openstack_nova.py b/collectd/files/plugin/openstack_nova.py
index ea2bd77..ecfee1e 100644
--- a/collectd/files/plugin/openstack_nova.py
+++ b/collectd/files/plugin/openstack_nova.py
@@ -23,7 +23,7 @@
 from itertools import groupby
 
 
-PLUGIN_NAME = 'nova'
+PLUGIN_NAME = 'openstack_nova'
 INTERVAL = openstack.INTERVAL
 
 
@@ -63,7 +63,7 @@
             yield {
                 'plugin_instance': 'instances',
                 'values': len(list(g)),
-                'type_instance': status,
+                'meta': {'state': status, 'discard_hostname': True},
             }
 
 
diff --git a/collectd/files/plugin/openstack_nova_services.py b/collectd/files/plugin/openstack_nova_services.py
index 51b0df4..c98840a 100644
--- a/collectd/files/plugin/openstack_nova_services.py
+++ b/collectd/files/plugin/openstack_nova_services.py
@@ -25,7 +25,7 @@
 
 import collectd_openstack as openstack
 
-PLUGIN_NAME = 'nova'
+PLUGIN_NAME = 'openstack_nova'
 INTERVAL = openstack.INTERVAL
 
 
@@ -55,9 +55,10 @@
 
             aggregated_workers[service][state] += 1
             yield {
-                'plugin_instance': 'nova_service',
+                'plugin_instance': 'service',
                 'values': self.states[state],
-                'meta': {'host': host, 'service': service, 'state': state}
+                'meta': {'hostname': host, 'service': service, 'state': state,
+                         'az': worker['zone']}
             }
 
         for service in set(aggregated_workers.keys()).union(
@@ -71,14 +72,16 @@
                     prct = (100.0 * aggregated_workers[service][state]) / total
 
                 yield {
-                    'plugin_instance': 'nova_services_percent',
+                    'plugin_instance': 'services_percent',
                     'values': prct,
-                    'meta': {'state': state, 'service': service},
+                    'meta': {'state': state, 'service': service,
+                             'discard_hostname': True},
                 }
                 yield {
-                    'plugin_instance': 'nova_services',
+                    'plugin_instance': 'services',
                     'values': aggregated_workers[service][state],
-                    'meta': {'state': state, 'service': service},
+                    'meta': {'state': state, 'service': service,
+                             'discard_hostname': True},
                 }