Add plugin Calico Felix
Change-Id: I5eb98f7edb38283e58b9706f899e2e641f407381
diff --git a/collectd/files/plugin/collectd_calico_felix.py b/collectd/files/plugin/collectd_calico_felix.py
new file mode 100644
index 0000000..f571796
--- /dev/null
+++ b/collectd/files/plugin/collectd_calico_felix.py
@@ -0,0 +1,157 @@
+#!/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 requests
+
+import collectd_base as base
+
+
+NAME = 'calico_felix'
+# Default sampling interval
+INTERVAL = 60
+
+
+class CalicoFelixPlugin(base.Base):
+
+ def __init__(self, *args, **kwargs):
+ super(CalicoFelixPlugin, self).__init__(*args, **kwargs)
+ self.plugin = NAME
+ self.session = requests.Session()
+ self.session.mount(
+ 'http://',
+ requests.adapters.HTTPAdapter(max_retries=self.max_retries)
+ )
+ self.session.mount(
+ 'https://',
+ requests.adapters.HTTPAdapter(max_retries=self.max_retries)
+ )
+ self.url = None
+
+ def config_callback(self, config):
+ super(CalicoFelixPlugin, self).config_callback(config)
+ for node in config.children:
+ self.logger.debug("Got config request for '{}': {}".format(
+ node.key.lower(), node.values[0])
+ )
+ if node.key.lower() == "url":
+ self.url = node.values[0]
+
+ def itermetrics(self):
+ if self.url:
+ self.logger.debug("Requesting URL {}".format(
+ self.url)
+ )
+ try:
+ r = self.session.get(self.url, timeout=self.timeout)
+ except Exception as e:
+ msg = "Got exception for '{}': {}".format(self.url, e)
+ raise base.CheckException(msg)
+
+ if r.status_code != 200:
+ self.logger.error(
+ ("{} responded with code {} "
+ "").format(self.url,
+ r.status_code))
+ raise base.CheckException(
+ "Failed to gather Calico Felix metrics ({})".format(
+ r.status_code
+ )
+ )
+ self.logger.debug(
+ "Got response from {}: '{}'"
+ "".format(self.url, r.text))
+ # Example payload:
+ # # HELP felix_active_local_endpoints Number
+ # # of active endpoints on this host.
+ # # TYPE felix_active_local_endpoints gauge
+ # felix_active_local_endpoints 1
+ # # HELP felix_iptables_chains Number of active iptables chains.
+ # # TYPE felix_iptables_chains gauge
+ # felix_iptables_chains{ip_version="4",table="filter"} 14
+ # felix_iptables_chains{ip_version="4",table="nat"} 6
+ # felix_iptables_chains{ip_version="4",table="raw"} 6
+ # felix_iptables_chains{ip_version="6",table="filter"} 14
+ # felix_iptables_chains{ip_version="6",table="nat"} 6
+ # felix_iptables_chains{ip_version="6",table="raw"} 6
+ # # HELP go_goroutines Number of goroutines that currently exist.
+ # # TYPE go_goroutineqs gauge
+ # go_goroutines 39
+ for l in r.text.split('\n'):
+ # Line is empty or is a comment
+ if not l or l.startswith('#'):
+ continue
+
+ (name, rval) = l.split()
+ self.logger.debug(
+ "Got val for {}: '{}'".format(name, rval))
+ # For some metrics, remove the existing felix prefix
+ # to ensure homogeneity
+ if name.startswith('felix_'):
+ name = name.replace('felix_', '', 1)
+ # Initialization of returned metric
+ ret_metric = {
+ 'values': rval
+ }
+ # Metric can have implicit dimensions. For example:
+ # felix_iptables_rules{ip_version="4",table="filter"}
+ m = re.search(
+ '^(?P<name>[^{]+)(?:{(?P<dimensions>.[^}]+)})?$',
+ name)
+ if not m:
+ self.logger.error(
+ "Error parsing metric name {}".format(
+ name))
+ continue
+
+ if m.group('dimensions'):
+ name = m.group('name')
+ meta = {}
+ for d in m.group('dimensions').split(','):
+ (k, v) = d.split('=')
+ meta[k] = v.strip('"')
+ if len(meta) > 0:
+ ret_metric['meta'] = meta
+ ret_metric['type_instance'] = m.group('name')
+ yield ret_metric
+
+
+plugin = CalicoFelixPlugin(collectd)
+
+
+def config_callback(conf):
+ plugin.config_callback(conf)
+
+
+def notification_callback(notification):
+ plugin.notification_callback(notification)
+
+
+def read_callback():
+ plugin.conditional_read_callback()
+
+if __name__ == '__main__':
+ collectd.load_configuration(plugin)
+ plugin.read_callback()
+else:
+ collectd.register_config(config_callback)
+ collectd.register_notification(notification_callback)
+ collectd.register_read(read_callback, INTERVAL)