Skip to content

Commit

Permalink
Add netbox Agent and checks
Browse files Browse the repository at this point in the history
  • Loading branch information
jiuka committed May 3, 2023
1 parent 45d4f52 commit af65bb7
Show file tree
Hide file tree
Showing 6 changed files with 394 additions and 9 deletions.
117 changes: 117 additions & 0 deletions agent_based/netbox_reports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-License
#
# Copyright (C) 2023 Marius Rieder <[email protected]>
#
# 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.

# <<<netbox_reports>>>
# 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)},
)
112 changes: 112 additions & 0 deletions agents/special/agent_netbox
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-License
#
# Copyright (C) 2023 Marius Rieder <[email protected]>
#
# 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('<<<netbox_reports:sep(44)>>>')
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()
25 changes: 25 additions & 0 deletions checks/agent_netbox
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-License
#
# Copyright (C) 2023 Marius Rieder <[email protected]>
#
# 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
21 changes: 12 additions & 9 deletions package
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
66 changes: 66 additions & 0 deletions web/plugins/wato/check_parameters_netbox_reports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
#
# Netbox Reports Last Run
#
# Copyright (C) 2023 Marius Rieder <[email protected]>
#
# 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'),
))
Loading

0 comments on commit af65bb7

Please sign in to comment.