diff --git a/agent_based/netbox_reports.py b/agent_based/netbox_reports.py new file mode 100644 index 0000000..dad708e --- /dev/null +++ b/agent_based/netbox_reports.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +# -*- encoding: utf-8; py-indent-offset: 4 -*-License +# +# Copyright (C) 2023 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# <<>> +# dellos6.DellOS6Report,DellOS6Report,test_device +# dellos6.DellOS6Report,DellOS6Report,test_interface +# devices.DeviceConnectionsReport,DeviceConnectionsReport,test_power_connections +# dhcp.DhcpReport,DhcpReport,test_pool_is_in_prefix,2023-01-04T08:00:01.134531+01:00,0,0,41,0 +# dhcp.DhcpReport,DhcpReport,test_prefix_has_pool,2023-01-04T08:00:01.134531+01:00,0,0,41,0 +# ipam.IpAddressReport,IpAddressReport,test_name_or_description,2022-12-22T14:20:32.555035+01:00,0,23,0,0 +# ipam.PrefixReport,PrefixReport,test_broadcast_reservation,2022-12-21T16:01:17.599839+01:00,0,0,101,0 +# ipam.PrefixReport,PrefixReport,test_no_subprefix_in_active,2022-12-21T16:01:17.599839+01:00,0,1,100,0 + +from .agent_based_api.v1 import ( + check_levels, + Metric, + register, + render, + Result, + Service, + State, +) + +from datetime import datetime + +def parse_netbox_reports(string_table): + parsed = {} + + for line in string_table: + if line[0] not in parsed: + parsed[line[0]] = {} + + parsed[line[0]][line[2]] = {} + + if len(line) == 3: + continue + + last_run_dt = datetime.fromisoformat(line[3]).replace(tzinfo=None) + + parsed[line[0]]['last_run'] = last_run_dt + parsed[line[0]][line[2]]['result'] = { + 'info': int(line[4]), + 'success': int(line[5]), + 'warning': int(line[6]), + 'failure': int(line[7]), + } + + # print (parsed) + return parsed + +register.agent_section( + name = "netbox_reports", + parse_function = parse_netbox_reports, +) + +def discover_netbox_reports(section): + for name in section: + yield Service(item=name) + +def check_netbox_reports(item, params, section): + + report = section[item] + + now = datetime.now() + if not 'last_run' in report: + yield Result(state=State.UNKNOWN, summary=(f"Report \"{item}\" not yet executed")) + else: + age = now - report['last_run'] + yield from check_levels( + value=age.total_seconds(), + levels_upper=params.get('maxage', None), + render_func=lambda f: render.timespan(f if f > 0 else -f), + label='Last Run' if age.total_seconds() > 0 else "Last Run in", + ) + + for test_name in report: + if test_name == 'last_run': + continue + + yield Result(state = State.OK, summary = f"{test_name}", + details = f"{test_name}: {report[test_name]['result']}") + + if report[test_name]['result']['warning'] > 0: + yield Result (state = State.WARN, + summary = f"Warning: {report[test_name]['result']['warning']}") + + if report[test_name]['result']['failure'] > 0: + yield Result (state = State.WARN, + summary = f"Failure: {report[test_name]['result']['failure']}") + + for key, value in report[test_name]['result'].items(): + yield Metric (f"{test_name}_{key}", value) + +register.check_plugin( + name = "netbox_reports", + service_name = "Netbox Reports %s", + discovery_function = discover_netbox_reports, + check_function = check_netbox_reports, + check_ruleset_name = "netbox_reports", + check_default_parameters = {'maxage': (2*24*3600, 7*24*3600)}, +) \ No newline at end of file diff --git a/agents/special/agent_netbox b/agents/special/agent_netbox new file mode 100644 index 0000000..acc0ad4 --- /dev/null +++ b/agents/special/agent_netbox @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8; py-indent-offset: 4 -*-License +# +# Copyright (C) 2023 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import logging +import requests +from functools import cached_property + +from cmk.special_agents.utils.agent_common import ( + special_agent_main, +) +from cmk.special_agents.utils.argument_parsing import ( + Args, + create_default_argument_parser, +) + +import urllib3 +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +LOGGING = logging.getLogger('agent_netbox') + +class AgentNetbox: + '''Checkmk special Agent for Netbox''' + + def run(self): + special_agent_main(self.parse_arguments, self.main) + + def parse_arguments(self, argv): + parser = create_default_argument_parser(description=self.__doc__) + + parser.add_argument('-U', '--url', + dest='url', + required=True, + help='Rest API URL of the Netbox. (Example https://netbox.example.com/api)') + parser.add_argument('-T', '--token', + dest='token', + required=True, + help='Netbox token.') + parser.add_argument('-t', '--timeout', + dest='timeout', + required=False, + default=10, + help='HTTP connection timeout. (Default: 10)') + + return parser.parse_args(argv) + + def main(self, args: Args): + self.args = args + + self.section_reports() + + def section_reports(self): + print('<<>>') + for report in self.get_reports(): + detail = self.get_report_detail(report) + for test_name in report['test_methods']: + if detail['data'] is None or test_name not in detail['data']: + print(",".join([ + report['id'], + report['name'], + test_name, + ])) + else: + data = detail['data'][test_name] + print(",".join([ + report['id'], + report['name'], + test_name, + detail['completed'] , + str(data['info']), + str(data['success']), + str(data['warning']), + str(data['failure']), + ])) + + + def get_reports(self): + response = self.client.get('{}/extras/reports/'.format(self.args.url), timeout=self.args.timeout) + return response.json() + + def get_report_detail(self, report): + if report['result'] is None: + return dict(data=None) + response = self.client.get(report['result']['url'], timeout=self.args.timeout) + return response.json() + + @cached_property + def client(self): + c = requests.Session() + c.headers.update({ + 'Accept': 'application/json', + 'Authorization': 'Token {}'.format(self.args.token) + }) + return c + +if __name__ == '__main__': + AgentNetbox().run() \ No newline at end of file diff --git a/checks/agent_netbox b/checks/agent_netbox new file mode 100644 index 0000000..28bb28a --- /dev/null +++ b/checks/agent_netbox @@ -0,0 +1,25 @@ +#!/usr/bin/python +# -*- encoding: utf-8; py-indent-offset: 4 -*-License +# +# Copyright (C) 2023 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +def agent_netbox_arguments(params, hostname, ipaddress): + args = ['--url', params['url'], '--token', passwordstore_get_cmdline('%s', params['token'])] + return args + +special_agent_info['netbox'] = agent_netbox_arguments \ No newline at end of file diff --git a/package b/package index e22a190..392c70a 100644 --- a/package +++ b/package @@ -1,20 +1,23 @@ { - 'author': u'', - 'description': u'', - 'download_url': '', + 'author': u'IT Team - Supercomputing Systems AG ', + 'description': u'Netbox Report Check', + 'download_url': 'https://github.com/scsitteam/checkmk_netbox', 'files': { - 'agent_based': [], - 'agents': [], + 'agent_based': ['netbox_reports'], + 'agents': ['special/agent_netbox'], 'checkman': [], - 'checks': [], + 'checks': ['agent_netbox'], 'doc': [], 'inventory': [], 'notifications': [], 'pnp-templates': [], - 'web': [] + 'web': [ + 'plugins/wato/check_parameters_netbox_reports.py', + 'plugins/wato/datasource_netbox.py', + ] }, - 'name': '', - 'title': u'', + 'name': 'Netbox', + 'title': u'Netbox', 'version': '0.1', 'version.min_required': '2.0.0', 'version.packaged': '2.0.0' diff --git a/web/plugins/wato/check_parameters_netbox_reports.py b/web/plugins/wato/check_parameters_netbox_reports.py new file mode 100644 index 0000000..0a7657d --- /dev/null +++ b/web/plugins/wato/check_parameters_netbox_reports.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +# Netbox Reports Last Run +# +# Copyright (C) 2023 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Age, + Dictionary, + TextAscii, + Tuple, +) + +from cmk.gui.plugins.wato import ( + CheckParameterRulespecWithItem, + rulespec_registry, + RulespecGroupCheckParametersApplications, +) + +def _item_spec_netbox_reports(): + return TextAscii(title=_('Name of the Netbox Report'), + allow_empty=False) + + +def _parameter_valuespec_netbox_reports(): + return Dictionary( + elements=[ + ( + 'maxage', + Tuple( + title=_('Maximal time since last run'), + elements=[ + Age(title=_('Warning if older than')), + Age(title=_('Critical if older than')), + ], + ) + ), + ], + ) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='netbox_reports', + group=RulespecGroupCheckParametersApplications, + item_spec=_item_spec_netbox_reports, + match_type='dict', + parameter_valuespec=_parameter_valuespec_netbox_reports, + title=lambda: _('Netbox Reports'), + )) \ No newline at end of file diff --git a/web/plugins/wato/datasource_netbox.py b/web/plugins/wato/datasource_netbox.py new file mode 100644 index 0000000..753fb37 --- /dev/null +++ b/web/plugins/wato/datasource_netbox.py @@ -0,0 +1,62 @@ +#!/usr/bin/python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +# Copyright (C) 2023 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from cmk.gui.i18n import _ +from cmk.gui.plugins.wato import ( + HostRulespec, + IndividualOrStoredPassword, + rulespec_registry, +) +from cmk.gui.valuespec import ( + Dictionary, + HTTPUrl, +) +from cmk.gui.plugins.wato.datasource_programs import RulespecGroupDatasourceProgramsApps + + +def _valuespec_special_agents_netbox(): + return Dictionary( + title=_("Netbox Server"), + help = _("This rule selects the Netbox agent"), + elements = [ + ( + 'url', + HTTPUrl( + title = _("URL of the Netbox Rest API, e.g. https://netbox.example.com/api"), + allow_empty = False, + ) + ), + ( + 'token', + IndividualOrStoredPassword( + title = _("Netbox Token"), + allow_empty = True, + ) + ), + ], + optional_keys = ['token'], + ) + + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupDatasourceProgramsApps, + name='special_agents:netbox', + valuespec=_valuespec_special_agents_netbox, + )) \ No newline at end of file