Add metrics for Nova aggregates
diff --git a/collectd/files/plugin/hypervisor_stats.py b/collectd/files/plugin/hypervisor_stats.py
index d03f7ae..ba6e050 100644
--- a/collectd/files/plugin/hypervisor_stats.py
+++ b/collectd/files/plugin/hypervisor_stats.py
@@ -42,21 +42,35 @@
         if 'cpu_ratio' not in self.extra_config:
             self.logger.warning('CpuAllocationRatio parameter not set')
 
-    def dispatch_value(self, name, value, host=None):
+    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={'0': True},
+            meta=meta or {'0': True},
             values=[value]
         )
-        if host:
-            v.host = host
         v.dispatch()
 
     def collect(self):
+        nova_aggregates = {}
+        r = self.get('nova', 'os-aggregates')
+        if not r:
+            self.logger.warning("Could not get nova aggregates")
+        else:
+            aggregates_list = r.json().get('aggregates', [])
+            for agg in aggregates_list:
+                nova_aggregates[agg['name']] = {
+                    'id': agg['id'],
+                    'hosts': agg['hosts'],
+                    'metrics': {'free_vcpus': 0},
+                }
+                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")
@@ -69,14 +83,48 @@
             # remove domain name and keep only the hostname portion
             host = stats['hypervisor_hostname'].split('.')[0]
             for k, v in self.VALUE_MAP.iteritems():
-                self.dispatch_value(v, stats.get(k, 0), host)
-                total_stats[v] += stats.get(k, 0)
+                m_val = stats.get(k, 0)
+                self.dispatch_value(v, m_val, {'host': host})
+                total_stats[v] += m_val
+                for agg in nova_aggregates.keys():
+                    agg_hosts = nova_aggregates[agg]['hosts']
+                    if stats['hypervisor_hostname'] in agg_hosts:
+                        nova_aggregates[agg]['metrics'][v] += m_val
             if 'cpu_ratio' in self.extra_config:
+                m_vcpus = stats.get('vcpus', 0)
+                m_vcpus_used = stats.get('vcpus_used', 0)
                 free = (int(self.extra_config['cpu_ratio'] *
-                        stats.get('vcpus', 0))) - stats.get('vcpus_used', 0)
-                self.dispatch_value('free_vcpus', free, host)
+                        m_vcpus)) - m_vcpus_used
+                self.dispatch_value('free_vcpus', free, {'host': 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:
+                        free = ((int(self.extra_config['cpu_ratio'] *
+                                     m_vcpus)) -
+                                m_vcpus_used)
+                        nova_aggregates[agg]['metrics']['free_vcpus'] += free
 
+        # Dispatch the aggregate metrics
+        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']
+            )
+            # 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
+            if agg_total_free_ram > 0:
+                nova_aggregates[agg]['metrics']['free_ram_percent'] = round(
+                    (100.0 * nova_aggregates[agg]['metrics']['free_ram_MB']) /
+                    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})
         # Dispatch the global metrics
         for k, v in total_stats.iteritems():
             self.dispatch_value('total_{}'.format(k), v)