blob: 5b519b811f867bbc8ef1457003e5f94bda6f033f [file] [log] [blame]
#!/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)