Skip to content
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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions sysutils/pfSense-pkg-node_exporter/Makefile
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
Copy link
Member

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.

${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/
Copy link
Member

Choose a reason for hiding this comment

The 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}
Copy link
Member

Choose a reason for hiding this comment

The 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}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this package is installing a python script, we need to have USES= python to make sure python is installed as a dependency. If it requires any extra python module available on ports, it also should be added to RUN_DEPENDS

@${REINPLACE_CMD} -i '' -e "s|%%PKGVERSION%%|${PKGVERSION}|" ${STAGEDIR}${DATADIR}/info.xml

.include <bsd.port.mk>
3 changes: 3 additions & 0 deletions sysutils/pfSense-pkg-node_exporter/files/pkg-deinstall.in
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}
7 changes: 7 additions & 0 deletions sysutils/pfSense-pkg-node_exporter/files/pkg-install.in
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
Copy link
Member

Choose a reason for hiding this comment

The 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"
1 change: 1 addition & 0 deletions sysutils/pfSense-pkg-node_exporter/pkg-descr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Prometheus exporter for machine metrics
Loading