-
Notifications
You must be signed in to change notification settings - Fork 598
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add pfSense-pkg-node_exporter #653
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# $FreeBSD$ | ||
|
||
PORTNAME= pfSense-pkg-node_exporter | ||
PORTVERSION= 0.18.1 | ||
CATEGORIES= sysutils | ||
MASTER_SITES= # empty | ||
DISTFILES= # empty | ||
EXTRACT_ONLY= # empty | ||
|
||
MAINTAINER= coreteam@pfsense.org | ||
COMMENT= pfSense package node_exporter | ||
|
||
LICENSE= APACHE20 | ||
|
||
RUN_DEPENDS= node_exporter>0:sysutils/node_exporter | ||
|
||
NO_BUILD= yes | ||
NO_MTREE= yes | ||
|
||
SUB_FILES= pkg-install pkg-deinstall | ||
SUB_LIST= PORTNAME=${PORTNAME} | ||
|
||
do-extract: | ||
${MKDIR} ${WRKSRC} | ||
|
||
do-install: | ||
${MKDIR} ${STAGEDIR}${PREFIX}/pkg | ||
${MKDIR} ${STAGEDIR}${PREFIX}/etc/rc.conf.d | ||
${MKDIR} ${STAGEDIR}${DATADIR} | ||
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/node_exporter.xml ${STAGEDIR}${PREFIX}/pkg | ||
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/node_exporter.inc ${STAGEDIR}${PREFIX}/pkg | ||
${INSTALL_DATA} ${FILESDIR}${PREFIX}/etc/rc.conf.d/node_exporter ${STAGEDIR}${PREFIX}/etc/rc.conf.d/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file doesn't exist, do not try to install it |
||
${INSTALL_DATA} ${FILESDIR}${DATADIR}/info.xml ${STAGEDIR}${DATADIR} | ||
${INSTALL_SCRIPT} ${FILESDIR}${DATADIR}/node_exporter.sh ${STAGEDIR}${DATADIR} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this file is really a copy of sysutils/node_exporter init script, we don't need to carry it here and it should be removed |
||
${INSTALL_SCRIPT} ${FILESDIR}${DATADIR}/interface-collector.py ${STAGEDIR}${DATADIR} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this package is installing a python script, we need to have |
||
@${REINPLACE_CMD} -i '' -e "s|%%PKGVERSION%%|${PKGVERSION}|" ${STAGEDIR}${DATADIR}/info.xml | ||
|
||
.include <bsd.port.mk> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/bin/sh | ||
|
||
/usr/local/bin/php -f /etc/rc.packages %%PORTNAME%% ${2} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/sh | ||
|
||
if [ "${2}" != "POST-INSTALL" ]; then | ||
exit 0 | ||
fi | ||
|
||
/usr/local/bin/php -f /etc/rc.packages %%PORTNAME%% ${2} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
<?php | ||
/* | ||
* node_exporter.inc | ||
* | ||
* part of pfSense (https://www.pfsense.org) | ||
* Copyright (c) 2009-2015 Rubicon Communications, LLC (Netgate) | ||
* All rights reserved. | ||
* | ||
* 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. | ||
*/ | ||
require_once("config.inc"); | ||
require_once("functions.inc"); | ||
require_once("util.inc"); | ||
require_once("service-utils.inc"); | ||
|
||
const NODE_EXPORTER_CONFIG_FILE = "/usr/local/etc/rc.conf.d/node_exporter"; | ||
const NODE_EXPORTER_RCFILE = "/usr/local/etc/rc.d/node_exporter.sh"; | ||
const NODE_EXPORTER_SHARE_DIR = "/usr/local/share/pfSense-pkg-node_exporter"; | ||
const NODE_EXPORTER_RCFILE_UPSTREAM = NODE_EXPORTER_SHARE_DIR . "/node_exporter.sh"; | ||
const NODE_EXPORTER_DEFAULT_COLLECTORS = "boottime,cpu,exec,filesystem,loadavg,meminfo,netdev,textfile,time"; | ||
const NODE_EXPORTER_TEXTFILE_CRONTASK = "/usr/bin/nice -n20 /usr/local/bin/python2.7 ".NODE_EXPORTER_SHARE_DIR."/interface-collector.py"; | ||
|
||
function node_exporter_write_config($node_exporter_config) { | ||
$txt = "# This file is generated by the pfSense node_exporter package.\n"; | ||
$txt .= "# Do not edit this file, it will be overwritten automatically.\n"; | ||
$txt .= "\n"; | ||
$txt .= "node_exporter_enable=\"YES\"\n"; // If it had been NO, this function isn't called, so fine to hardcode | ||
|
||
$listen_addr = get_interface_ip($node_exporter_config["listen_iface"]); | ||
$listen_port = $node_exporter_config["listen_port"] ?: "9100"; | ||
$txt .= "node_exporter_listen_address=\"{$listen_addr}:{$listen_port}\"\n"; | ||
|
||
$collectorTxt = ""; | ||
foreach (explode(",", $node_exporter_config["collectors"]) as $collector) { | ||
$collectorTxt .= " --collector.".$collector; | ||
} | ||
|
||
$txt .= "node_exporter_args=\"{$collectorTxt} {$node_exporter_config['extra_flags']}\"\n"; | ||
|
||
if (!file_put_contents(NODE_EXPORTER_CONFIG_FILE, $txt)) { | ||
log_error("ERROR: Could not open {" . NODE_EXPORTER_CONFIG_FILE . "} for writing"); | ||
exit; | ||
} | ||
} | ||
function node_exporter_sync_config() { | ||
global $config; | ||
if (is_service_running('node_exporter')) { | ||
log_error("Stopping service node_exporter"); | ||
stop_service('node_exporter'); | ||
} | ||
|
||
$node_exporter_config = &$config['installedpackages']['nodeexporter']['config'][0]; | ||
if ($node_exporter_config['enable'] !== 'on') { | ||
unlink_if_exists(NODE_EXPORTER_RCFILE); | ||
return; | ||
} | ||
/* Write the config file */ | ||
node_exporter_write_config($node_exporter_config); | ||
|
||
/* Copy the rc script from the upstream one we bundle */ | ||
if (!copy(NODE_EXPORTER_RCFILE_UPSTREAM, NODE_EXPORTER_RCFILE)) { | ||
log_error("ERROR: Could not copy {" . NODE_EXPORTER_RCFILE_UPSTREAM . "} to {" . NODE_EXPORTER_RCFILE . "}"); | ||
exit; | ||
} | ||
if (!chmod(NODE_EXPORTER_RCFILE, 0755)) { | ||
log_error("ERROR: Could not set permissions on {" . NODE_EXPORTER_RCFILE . "}"); | ||
exit; | ||
} | ||
|
||
if (platform_booting()) { | ||
return; | ||
} | ||
log_error("Starting service node_exporter"); | ||
start_service('node_exporter'); | ||
} | ||
|
||
function node_exporter_install_command() { | ||
global $config; | ||
|
||
// If instaing for the first time, set up the default config | ||
$node_exporter_config = &$config['installedpackages']['nodeexporter']['config'][0]; | ||
if (!is_array($node_exporter_config)) { | ||
$node_exporter_config = [ | ||
"collectors" => NODE_EXPORTER_DEFAULT_COLLECTORS, | ||
"listen_port" => "9100", | ||
"extra_flags" => "--log.level=warn", | ||
]; | ||
} | ||
|
||
// Set up textfile cron job | ||
install_cron_job(NODE_EXPORTER_TEXTFILE_CRONTASK, true, "*"); | ||
|
||
node_exporter_sync_config(); | ||
} | ||
|
||
function node_exporter_deinstall_command() { | ||
if (is_service_running('node_exporter')) { | ||
log_error("Stopping service node_exporter"); | ||
stop_service('node_exporter'); | ||
} | ||
unlink_if_exists(NODE_EXPORTER_RCFILE); | ||
unlink_if_exists(NODE_EXPORTER_CONFIG_FILE); | ||
|
||
// Set up textfile cron job | ||
install_cron_job(NODE_EXPORTER_TEXTFILE_CRONTASK, false); | ||
} | ||
|
||
function node_exporter_validate_form($post, &$input_errors) { | ||
if (empty($post['listen_iface'])) { | ||
$input_errors[] = gettext('You must select an interface to listen to'); | ||
} | ||
|
||
if (!is_port($post['listen_port'])) { | ||
$input_errors[] = gettext('You must enter a valid port number in the \'Listen Port\' field'); | ||
} | ||
} | ||
|
||
?> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> | ||
<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> | ||
<packagegui> | ||
<copyright> | ||
<![CDATA[ | ||
/* | ||
* node_exporter.xml | ||
* | ||
* part of pfSense (https://www.pfsense.org) | ||
* Copyright (c) 2009-2015 Rubicon Communications, LLC (Netgate) | ||
* All rights reserved. | ||
* | ||
* 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. | ||
*/ | ||
]]> | ||
</copyright> | ||
<title>node_exporter</title> | ||
<name>node_exporter</name> | ||
<include_file>/usr/local/pkg/node_exporter.inc</include_file> | ||
<menu> | ||
<name>Prometheus node_exporter</name> | ||
<tooltiptext>Setup node_exporter specific settings</tooltiptext> | ||
<section>Services</section> | ||
<url>/pkg_edit.php?xml=node_exporter.xml</url> | ||
</menu> | ||
<service> | ||
<name>node_exporter</name> | ||
<rcfile>node_exporter.sh</rcfile> | ||
<executable>node_exporter</executable> | ||
<description>node_exporter</description> | ||
</service> | ||
<fields> | ||
<field> | ||
<fielddescr>Enable node_exporter</fielddescr> | ||
<fieldname>enable</fieldname> | ||
<type>checkbox</type> | ||
</field> | ||
<field> | ||
<fielddescr>Interface</fielddescr> | ||
<fieldname>listen_iface</fieldname> | ||
<type>interfaces_selection</type> | ||
<description>Pick an interface to serve the metrics endpoint on.</description> | ||
<hideinterfaceregex>wan</hideinterfaceregex> | ||
</field> | ||
<field> | ||
<fielddescr>Listen port</fielddescr> | ||
<fieldname>listen_port</fieldname> | ||
<type>input</type> | ||
<description>Pick the port to serve the metrics endpoint on.</description> | ||
</field> | ||
|
||
<field> | ||
<fielddescr>Collectors</fielddescr> | ||
<fieldname>collectors</fieldname> | ||
<description>Select enabled collectors. Those marked with (*) are the default set.</description> | ||
<type>select</type> | ||
<multiple /> | ||
<size>15</size> | ||
<options> | ||
<option><name>boottime (*)</name><value>boottime</value></option> | ||
<option><name>buddyinfo</name><value>buddyinfo</value></option> | ||
<option><name>cpu (*)</name><value>cpu</value></option> | ||
<option><name>exec (*)</name><value>exec</value></option> | ||
<option><name>filesystem (*)</name><value>filesystem</value></option> | ||
<option><name>loadavg (*)</name><value>loadavg</value></option> | ||
<option><name>meminfo (*)</name><value>meminfo</value></option> | ||
<option><name>netdev (*)</name><value>netdev</value></option> | ||
<option><name>ntp</name><value>ntp</value></option> | ||
<option><name>runit</name><value>runit</value></option> | ||
<option><name>supervisord</name><value>supervisord</value></option> | ||
<option><name>textfile (*)</name><value>textfile</value></option> | ||
<option><name>time (*)</name><value>time</value></option> | ||
<option><name>devstat</name><value>devstat</value></option> | ||
</options> | ||
</field> | ||
|
||
<field> | ||
<fielddescr>Extra flags</fielddescr> | ||
<fieldname>extra_flags</fieldname> | ||
<type>input</type> | ||
<description>Extra flags to pass</description> | ||
</field> | ||
</fields> | ||
<custom_php_validation_command>node_exporter_validate_form($_POST, $input_errors);</custom_php_validation_command> | ||
<custom_php_resync_config_command>node_exporter_sync_config();</custom_php_resync_config_command> | ||
<custom_php_pre_deinstall_command>node_exporter_deinstall_command();</custom_php_pre_deinstall_command> | ||
<custom_php_install_command>node_exporter_install_command();</custom_php_install_command> | ||
</packagegui> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0"?> | ||
<pfsensepkgs> | ||
<package> | ||
<name>node_exporter</name> | ||
<descr>Prometheus exporter for machine metrics</descr> | ||
<website>http://github.com/prometheus/node_exporter</website> | ||
<version>%%PKGVERSION%%</version> | ||
<configurationfile>node_exporter.xml</configurationfile> | ||
</package> | ||
</pfsensepkgs> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/usr/bin/env python | ||
carlpett marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import xml.etree.ElementTree as ET | ||
|
||
class simplemetric: | ||
template = """# HELP {name} {help} | ||
# TYPE {name} gauge | ||
{series}""" | ||
def __init__(self, name, help): | ||
self.name = name | ||
self.help = help | ||
self.series = [] | ||
def __str__(self): | ||
return simplemetric.template.format(name=self.name, help=self.help, series='\n'.join(self.series)) | ||
def __repr__(self): | ||
return self.__str__() | ||
def add(self, val, **labelpairs): | ||
lvs = ['{key}="{value}"'.format(key=key, value=value) for key,value in list(labelpairs.items())] | ||
self.series.append('{name}{{{labels}}} {val}'.format(name=self.name, labels=','.join(lvs), val=val)) | ||
|
||
metrics = { | ||
'up': simplemetric('node_pfsense_interface_up','1 if interface is enabled, else 0.'), | ||
'info': simplemetric('node_pfsense_interface_info', 'Information about the interface. Always 1.') | ||
} | ||
|
||
root = ET.parse('/conf/config.xml') | ||
for elem in root.find("interfaces"): | ||
pf_name = elem.tag | ||
if_name = elem.find('if').text | ||
descr = elem.find('descr').text | ||
enabled = 1 if elem.find('enable') is not None else 0 | ||
metrics['up'].add(enabled, name=pf_name) | ||
metrics['info'].add(enabled, description=descr, interface=if_name, name=pf_name) | ||
|
||
textfile = open('/var/tmp/node_exporter/pfsense.prom','w') | ||
textfile.write('\n'.join(str(m) for m in list(metrics.values()))) | ||
textfile.write('\n') # Ensure trailing newline |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#!/bin/sh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file seems to be a copy of sysutils/node_exporter init script, we don't need to carry it here |
||
|
||
# PROVIDE: node_exporter | ||
# REQUIRE: LOGIN | ||
# KEYWORD: shutdown | ||
# | ||
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf | ||
# to enable this service: | ||
# | ||
# node_exporter_enable (bool): Set to NO by default. | ||
# Set it to YES to enable node_exporter. | ||
# node_exporter_user (string): Set user that node_exporter will run under | ||
# Default is "nobody". | ||
# node_exporter_group (string): Set group that node_exporter will run under | ||
# Default is "nobody". | ||
# node_exporter_args (string): Set extra arguments to pass to node_exporter | ||
# Default is "". | ||
# node_exporter_listen_address (string):Set ip:port that node_exporter will listen on | ||
# Default is ":9100". | ||
# node_exporter_textfile_dir (string): Set directory that node_exporter will watch | ||
# Default is "/var/tmp/node_exporter". | ||
|
||
. /etc/rc.subr | ||
|
||
name=node_exporter | ||
rcvar=node_exporter_enable | ||
|
||
load_rc_config $name | ||
|
||
: ${node_exporter_enable:="NO"} | ||
: ${node_exporter_user:="nobody"} | ||
: ${node_exporter_group:="nobody"} | ||
: ${node_exporter_args:=""} | ||
: ${node_exporter_listen_address:=":9100"} | ||
: ${node_exporter_textfile_dir:="/var/tmp/node_exporter"} | ||
|
||
|
||
pidfile=/var/run/node_exporter.pid | ||
command="/usr/sbin/daemon" | ||
procname="/usr/local/bin/node_exporter" | ||
command_args="-p ${pidfile} -T ${name} \ | ||
/usr/bin/env ${procname} \ | ||
--web.listen-address=${node_exporter_listen_address} \ | ||
--collector.textfile.directory=${node_exporter_textfile_dir} \ | ||
${node_exporter_args}" | ||
|
||
start_precmd=node_exporter_startprecmd | ||
|
||
node_exporter_startprecmd() | ||
{ | ||
if [ ! -e ${pidfile} ]; then | ||
install \ | ||
-o ${node_exporter_user} \ | ||
-g ${node_exporter_group} \ | ||
/dev/null ${pidfile}; | ||
fi | ||
if [ ! -d ${node_exporter_textfile_dir} ]; then | ||
install \ | ||
-d \ | ||
-o ${node_exporter_user} \ | ||
-g ${node_exporter_group} \ | ||
-m 1755 \ | ||
${node_exporter_textfile_dir} | ||
fi | ||
} | ||
|
||
load_rc_config $name | ||
run_rc_command "$1" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Prometheus exporter for machine metrics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No files are going to be installed here, no need to create this directory.