Use (Prometheus) node_exporter to expose metrics.

This new plugin allows for Prometheus to scrape an OPNsense installation for
metrics - including CPU, Memory, devices, interfaces and so on.

The data can then be used for remote monitoring/alerting of an OPNsense
installation, or indeed graphing using popular graphing technologies such as
Grafana.

closes #452

-=david=-
This commit is contained in:
David Harrigan 2017-12-25 20:57:58 +00:00
parent 94de7141cb
commit 80f02ea55c
15 changed files with 521 additions and 0 deletions

View file

@ -0,0 +1,7 @@
PLUGIN_NAME= node_exporter
PLUGIN_VERSION= 0.1.0
PLUGIN_COMMENT= Prometheus Node Exporter
PLUGIN_DEPENDS= node_exporter
PLUGIN_MAINTAINER= dharrigan@gmail.com
.include "../../Mk/plugins.mk"

View file

@ -0,0 +1,4 @@
Prometheus exporter for hardware and OS metrics exposed by *NIX kernels,
written in Go with pluggable metric collectors.
WWW: https://github.com/prometheus/node_exporter

View file

@ -0,0 +1,52 @@
<?php
/*
* Copyright (C) 2018 David Harrigan
* Copyright (C) 2017 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
function node_exporter_services()
{
$services = array();
$mdlGeneral = new \OPNsense\NodeExporter\General();
if ($mdlGeneral->enabled->__toString() == "0") {
return $services;
}
$services[] = array(
'description' => gettext('Prometheus Node Exporter'),
'configd' => array(
'restart' => array('node_exporter restart'),
'start' => array('node_exporter start'),
'stop' => array('node_exporter stop'),
'status' => array('node_exporter status'),
),
'name' => 'node_exporter',
'pidfile' => '/var/run/node_exporter.pid'
);
return $services;
}

View file

@ -0,0 +1,40 @@
<?php
/**
* Copyright (C) 2018 David Harrigan.
* Copyright (C) 2015 - 2017 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\NodeExporter\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
class GeneralController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'general';
static protected $internalModelClass = 'OPNsense\NodeExporter\General';
}

View file

@ -0,0 +1,42 @@
<?php
/**
* Copyright (C) 2018 David Harrigan.
* Copyright (C) 2015 - 2017 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\NodeExporter\Api;
use \OPNsense\Base\ApiMutableServiceControllerBase;
class ServiceController extends ApiMutableServiceControllerBase
{
static protected $internalServiceClass = '\OPNsense\NodeExporter\General';
static protected $internalServiceEnabled = 'enabled';
static protected $internalServiceTemplate = 'OPNsense/NodeExporter';
static protected $internalServiceName = 'node_exporter';
}

View file

@ -0,0 +1,41 @@
<?php
/**
* Copyright (C) 2018 David Harrigan
* Copyright (C) 2015 - 2017 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\NodeExporter;
use \OPNsense\Base\IndexController;
class GeneralController extends IndexController
{
public function indexAction()
{
$this->view->pick('OPNsense/NodeExporter/general');
$this->view->generalForm = $this->getForm("general");
}
}

View file

@ -0,0 +1,80 @@
<form>
<field>
<id>general.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will activate the node_exporter plugin.</help>
</field>
<field>
<id>general.listenaddress</id>
<label>Listen Address</label>
<type>text</type>
<help>Set node_exporter's listen address. By default, node_exporter will listen on 0.0.0.0 (all interfaces).</help>
</field>
<field>
<id>general.listenport</id>
<label>Listen Port</label>
<type>text</type>
<help>Set node_exporter's listen port. By default, node_exporter will listen on port 9100.</help>
</field>
<field>
<id>general.cpu</id>
<label>CPU Statistics</label>
<type>checkbox</type>
<help>Enable the CPU collector.</help>
</field>
<field>
<id>general.exec</id>
<label>Execution Statistics</label>
<type>checkbox</type>
<help>Enable the EXEC collector.</help>
</field>
<field>
<id>general.filesystem</id>
<label>Filesystem Statistics</label>
<type>checkbox</type>
<help>Enable the FILESYSTEM collector.</help>
</field>
<field>
<id>general.loadavg</id>
<label>Load Average Statistics</label>
<type>checkbox</type>
<help>Enable the LOADAVG collector.</help>
</field>
<field>
<id>general.meminfo</id>
<label>Memory Statistics</label>
<type>checkbox</type>
<help>Enable the MEMINFO collector.</help>
</field>
<field>
<id>general.netdev</id>
<label>Network Interface Statistics</label>
<type>checkbox</type>
<help>Enable the NETDEV collector.</help>
</field>
<field>
<id>general.time</id>
<label>Current Time Statistics</label>
<type>checkbox</type>
<help>Enable the TIME collector.</help>
</field>
<field>
<id>general.devstat</id>
<label>Device Statistics</label>
<type>checkbox</type>
<help>Enable the DEVSTAT collector.</help>
</field>
<field>
<id>general.interrupts</id>
<label>Interrupts Statistics</label>
<type>checkbox</type>
<help>Enable the INTERRUPTS collector.</help>
</field>
<field>
<id>general.ntp</id>
<label>NTP Statistics</label>
<type>checkbox</type>
<help>Enable the NTP collector.</help>
</field>
</form>

View file

@ -0,0 +1,9 @@
<acl>
<page-services-nodeexporter>
<name>Services: Prometheus Node Exporter</name>
<patterns>
<pattern>ui/nodeexporter/*</pattern>
<pattern>api/nodeexporter/*</pattern>
</patterns>
</page-services-nodeexporter>
</acl>

View file

@ -0,0 +1,37 @@
<?php
/**
* Copyright (C) 2018 David Harrigan
* Copyright (C) 2017 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\NodeExporter;
use OPNsense\Base\BaseModel;
class General extends BaseModel
{
}

View file

@ -0,0 +1,66 @@
<model>
<mount>//OPNsense/NodeExporter</mount>
<description>
node_exporter - Prometheus exporter for hardware and OS metrics.
</description>
<version>0.1.0</version>
<items>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<listenaddress type="TextField">
<default>0.0.0.0</default>
<Required>Y</Required>
<mask>/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-4]|2[0-5][0-9]|[01]?[0-9][0-9]?)$/</mask>
<ValidationMessage>Please provide a valid IPv4 address.</ValidationMessage>
</listenaddress>
<listenport type="IntegerField">
<default>9100</default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>65535</MaximumValue>
<ValidationMessage>Please provide a valid port number between 1 and 65535. Port 9100 is the default.</ValidationMessage>
</listenport>
<cpu type="BooleanField">
<default>1</default>
<Required>N</Required>
</cpu>
<exec type="BooleanField">
<default>1</default>
<Required>N</Required>
</exec>
<filesystem type="BooleanField">
<default>1</default>
<Required>N</Required>
</filesystem>
<loadavg type="BooleanField">
<default>1</default>
<Required>N</Required>
</loadavg>
<meminfo type="BooleanField">
<default>1</default>
<Required>N</Required>
</meminfo>
<netdev type="BooleanField">
<default>1</default>
<Required>N</Required>
</netdev>
<time type="BooleanField">
<default>1</default>
<Required>N</Required>
</time>
<devstat type="BooleanField">
<default>0</default>
<Required>N</Required>
</devstat>
<interrupts type="BooleanField">
<default>0</default>
<Required>N</Required>
</interrupts>
<ntp type="BooleanField">
<default>0</default>
<Required>N</Required>
</ntp>
</items>
</model>

View file

@ -0,0 +1,5 @@
<menu>
<Services>
<NodeExporter VisibleName="Node Exporter" cssClass="fa fa-area-chart" url="/ui/nodeexporter/general/index"/>
</Services>
</menu>

View file

@ -0,0 +1,62 @@
{#
Copyright (C) 2018 David Harrigan
OPNsense® is Copyright © 2015 2017 by Deciso B.V.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
#}
<script type="text/javascript">
$(document).ready(function() {
var data_get_map = {'frm_general_settings':"/api/nodeexporter/general/get"};
mapDataToFormUI(data_get_map).done(function(data) {
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
ajaxCall(url="/api/nodeexporter/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
$("#saveAct").click(function() {
saveFormToEndpoint(url="/api/nodeexporter/general/set", formid='frm_general_settings',callback_ok=function() {
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/nodeexporter/service/reconfigure", sendData={}, callback=function(data,status) {
ajaxCall(url="/api/nodeexporter/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
});
</script>
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form", ['fields':generalForm,'id':'frm_general_settings']) }}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b> <i id="saveAct_progress"></i></button>
</div>
</div>

View file

@ -0,0 +1,23 @@
[start]
command: /usr/local/etc/rc.d/node_exporter start
parameters:
type: script
message: Start Node Exporter Service
[stop]
command: /usr/local/etc/rc.d/node_exporter stop
parameters:
type: script
message: Stop Node Exporter Service
[restart]
command: /usr/local/etc/rc.d/node_exporter restart
parameters:
type: script
message: Restart Node Exporter Service
[status]
command: /usr/local/etc/rc.d/node_exporter status;exit 0
parameters:
type: script_output
message: Request Node Exporter Status

View file

@ -0,0 +1 @@
node_exporter:/etc/rc.conf.d/node_exporter

View file

@ -0,0 +1,52 @@
#
# This file is automatically generated. Do not manually edit this file - changes *will* be lost!
#
{% if helpers.exists('OPNsense.NodeExporter.enabled') and OPNsense.NodeExporter.enabled == '1' %}
{%- set collector = "--collector." -%}
{%- if OPNsense.NodeExporter.cpu == '1' -%}
{%- set cpu = collector + "cpu " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.exec == '1' -%}
{%- set exec = collector + "exec " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.filesystem == '1' -%}
{%- set filesystem = collector + "filesystem " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.loadavg == '1' -%}
{%- set loadavg = collector + "loadavg " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.meminfo == '1' -%}
{%- set meminfo = collector + "meminfo " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.netdev == '1' -%}
{%- set netdev = collector + "netdev " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.ntp == '1' -%}
{%- set ntp = collector + "ntp " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.time == '1' -%}
{%- set time = collector + "time " -%}
{%- endif -%}
{%- if OPNsense.NodeExporter.devstat == '1' -%}
{%- set devstat = collector + "devstat " -%}
{%- endif -%}
node_exporter_args="{{ cpu }}{{ exec }}{{ filesystem }}{{ loadavg }}{{ meminfo }}{{ netdev }}{{ ntp }}{{ time }}{{ devstat }}"
node_exporter_listen_address="{{ OPNsense.NodeExporter.listenaddress }}:{{ OPNsense.NodeExporter.listenport }}"
node_exporter_enable="YES"
{%- else -%}
node_exporter_enable="NO"
{%- endif -%}