feature: Added ZFS support for FreeBSD (#7938)

* add the ZFS graphs

* And now the ZFS non-graph stuff.

Still need to move it over to using JSON.

* Now uses JSON.

* use stripslashes as SNMPD loves to slash up the JSON

* Document ZFS.

* very minor formatting cleanup

* minor formatting cleanup and remove a bit of code from when I was mucking around debugging it all
This commit is contained in:
VVelox
2017-12-30 05:42:51 -06:00
committed by Neil Lathwood
parent 0e13e77c5f
commit eaf70e96f6
18 changed files with 858 additions and 1 deletions

View File

@@ -42,6 +42,7 @@ Different applications support a variety of ways to collect data: by direct conn
1. [Unbound](#unbound) - Agent
1. [UPS-nut](#ups-nut) - SNMP extend
1. [UPS-apcups](#ups-apcups) - SNMP extend
1. [ZFS](#zfs) - SNMP extend
### Apache
Either use SNMP extend or use the agent.
@@ -953,3 +954,22 @@ extend sdfsinfo /etc/snmp/sdfsinfo
4. Restart snmpd on your host
5. On the device page in Librenms, edit your host and check the `SDFS info` under the Applications tab or wait for it to be auto-discovered.
### ZFS
###### SNMP Extend
1. Copy the perl script to the desired host (the host must be added to LibreNMS devices)
```
wget https://github.com/librenms/librenms-agent/raw/master/snmp/zfs-freebsd -O /etc/snmp/zfs-freebsd
```
2. Make the script executable (chmod +x /etc/snmp/zfs-freebsd)
3. Edit your snmpd.conf file (usually /etc/snmp/snmpd.conf) and add:
```
extend zfs /etc/snmp/zfs-freebsd
```
4. Restart snmpd on your host
At this time, only FreeBSD is support. Linux support is eventually planned.

View File

@@ -132,6 +132,9 @@ function nicecase($item)
case 'freeradius':
return 'FreeRADIUS';
case 'zfs':
return 'ZFS';
default:
return ucfirst($item);
}
@@ -1663,3 +1666,28 @@ function generate_stacked_graphs($transparency = '88')
return array('transparency' => '', 'stacked' => '-1');
}
}
/**
* Get the ZFS pools for a device... just requires the device ID
* an empty return means ZFS is not in use or there are currently no pools
* @param $device_id
* @return array
*/
function get_zfs_pools($device_id)
{
$options=array(
'filter' => array(
'type' => array('=', 'zfs'),
),
);
$component=new LibreNMS\Component();
$zfsc=$component->getComponents($device_id, $options);
if (isset($zfsc[$device_id])) {
$id = $component->getFirstComponentID($zfsc, $device_id);
return json_decode($zfsc[$device_id][$id]['pools']);
}
return array();
}

View File

@@ -0,0 +1,71 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'hits/second';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand',
'ds' => 'demand_data_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand Meta',
'ds' => 'demand_meta_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'MRU',
'ds' => 'mru_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'MRU Ghost',
'ds' => 'mru_ghost_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'MFU',
'ds' => 'mfu_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'MFU Ghost',
'ds' => 'mfu_ghost_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch',
'ds' => 'pre_data_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch Meta',
'ds' => 'pre_meta_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Anonymous',
'ds' => 'anon_hits',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'ARC',
'ds' => 'arc_hits',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,45 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = '% of Hits';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Anon Used',
'ds' => 'anon_hits_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Most Recent',
'ds' => 'mru_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Most Frequent',
'ds' => 'mfu_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'MRU Ghost',
'ds' => 'mru_ghost_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'MFU Ghost',
'ds' => 'mfu_ghost_per',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,40 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = '% of Hits';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand',
'ds' => 'demand_hits_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch',
'ds' => 'pre_hits_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand Meta',
'ds' => 'meta_hits_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch Meta',
'ds' => 'pre_meta_hits_per',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,45 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'misses/second';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand',
'ds' => 'demand_data_misses',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand Meta',
'ds' => 'demand_meta_misses',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch',
'ds' => 'pre_data_misses',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch Meta',
'ds' => 'pre_meta_misses',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'ARC',
'ds' => 'arc_misses',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,40 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = '% of Misses';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand',
'ds' => 'demand_misses_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch',
'ds' => 'pre_misses_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Demand Meta',
'ds' => 'meta_misses_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Prefetch Meta',
'ds' => 'pre_meta_misses_per',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,40 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'percent';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Cache Hit',
'ds' => 'cache_hits_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Cache Miss',
'ds' => 'cache_miss_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Actual Hit',
'ds' => 'actual_hit_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Data Demand',
'ds' => 'data_demand_per',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,40 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'per second';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Deleted',
'ds' => 'deleted',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Recycle Misses',
'ds' => 'recycle_miss',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Evict Skip',
'ds' => 'evict_skip',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Mutex Skip',
'ds' => 'mutex_skip',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,40 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'bytes';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'ARC Size',
'ds' => 'arc_size',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Target Size',
'ds' => 'target_size',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Target Max',
'ds' => 'target_size_max',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Target Min',
'ds' => 'target_size_min',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,30 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'bytes';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Frequently Used',
'ds' => 'mfu_size',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Recently Used',
'ds' => 'p',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,35 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = '% of Max';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'ARC Size%',
'ds' => 'arc_size_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Target Size%',
'ds' => 'target_size_per',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Target Min%',
'ds' => 'min_size_per',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,25 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'percent';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id'], $vars['pool']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Capacity',
'ds' => 'cap',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,25 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'percent';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id'], $vars['pool']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Frag',
'ds' => 'frag',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -0,0 +1,40 @@
<?php
$name = 'zfs';
$app_id = $app['app_id'];
$unit_text = 'bytes';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 1;
$transparency = 15;
$rrd_filename = rrd_name($device['hostname'], array('app', $name, $app['app_id'], $vars['pool']));
$rrd_list=array();
if (rrdtool_check_rrd_exists($rrd_filename)) {
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Size',
'ds' => 'size',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Allocated',
'ds' => 'alloc',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Free',
'ds' => 'free',
);
$rrd_list[]=array(
'filename' => $rrd_filename,
'descr' => 'Expand Size',
'ds' => 'expandsz',
);
} else {
d_echo('RRD "'.$rrd_filename.'" not found');
}
require 'includes/graphs/generic_multi_line.inc.php';

View File

@@ -283,6 +283,19 @@ $graphs['freeradius'] = array(
'queue',
);
$graphs['zfs'] = array(
'arc_misc',
'arc_size',
'arc_size_per',
'arc_size_breakdown',
'arc_efficiency',
'arc_cache_hits_by_list',
'arc_cache_hits_by_type',
'arc_cache_misses_by_type',
'arc_cache_hits',
'arc_cache_miss',
);
print_optionbar_start();
echo "<span style='font-weight: bold;'>Apps</span> &#187; ";

View File

@@ -0,0 +1,83 @@
<?php
global $config;
$pools=get_zfs_pools($device['device_id']);
$link_array = array(
'page' => 'device',
'device' => $device['device_id'],
'tab' => 'apps',
'app' => 'zfs',
);
print_optionbar_start();
echo generate_link('ARC', $link_array);
echo '| Pools:';
$pool_int=0;
while (isset($pools[$pool_int])) {
$pool=$pools[$pool_int];
$label=$pool;
if ($vars['pool'] == $pool) {
$label='>>'.$pool.'<<';
}
$pool_int++;
$append='';
if (isset($pools[$pool_int])) {
$append=', ';
}
echo generate_link($label, $link_array, array('pool'=>$pool)).$append;
}
print_optionbar_end();
if (!isset($vars['pool'])) {
$graphs = array(
'zfs_arc_misc' => 'ARC misc',
'zfs_arc_size' => 'ARC size in bytes',
'zfs_arc_size_per' => 'ARC size, percent of max size',
'zfs_arc_size_breakdown' => 'ARC size breakdown',
'zfs_arc_efficiency' => 'ARC efficiency',
'zfs_arc_cache_hits_by_list' => 'ARC cache hits by list',
'zfs_arc_cache_hits_by_type' => 'ARC cache hits by type',
'zfs_arc_cache_misses_by_type' => 'ARC cache misses by type',
'zfs_arc_cache_hits' => 'ARC cache hits',
'zfs_arc_cache_miss' => 'ARC cache misses',
);
} else {
$graphs = array(
'zfs_pool_space'=>'Pool Space',
'zfs_pool_cap'=>'Pool Capcity',
'zfs_pool_frag'=>'Pool Fragmentation',
);
}
foreach ($graphs as $key => $text) {
$graph_type = $key;
$graph_array['height'] = '100';
$graph_array['width'] = '215';
$graph_array['to'] = $config['time']['now'];
$graph_array['id'] = $app['app_id'];
$graph_array['type'] = 'application_'.$key;
if (isset($vars['pool'])) {
$graph_array['pool']=$vars['pool'];
}
echo '<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">'.$text.'</h3>
</div>
<div class="panel-body">
<div class="row">';
include 'includes/print-graphrow.inc.php';
echo '</div>';
echo '</div>';
echo '</div>';
}

View File

@@ -0,0 +1,197 @@
<?php
use LibreNMS\RRD\RrdDefinition;
echo ' zfs ';
$name = 'zfs';
$app_id = $app['app_id'];
$options = '-O qv';
$mib = 'NET-SNMP-EXTEND-MIB';
$oid = 'nsExtendOutputFull.3.122.102.115';
$json = snmp_get($device, $oid, $options, $mib);
$zfs=json_decode(stripslashes($json), true);
$rrd_name = array('app', $name, $app_id);
$rrd_def = RrdDefinition::make()
->addDataset('deleted', 'DERIVE', 0)
->addDataset('evict_skip', 'DERIVE', 0)
->addDataset('mutex_skip', 'DERIVE', 0)
->addDataset('recycle_miss', 'DERIVE', 0)
->addDataset('arc_size', 'GAUGE', 0)
->addDataset('target_size_max', 'GAUGE', 0)
->addDataset('target_size_min', 'GAUGE', 0)
->addDataset('target_size', 'GAUGE', 0)
->addDataset('target_size_per', 'GAUGE', 0)
->addDataset('arc_size_per', 'GAUGE', 0)
->addDataset('target_size_arat', 'GAUGE', 0)
->addDataset('min_size_per', 'GAUGE', 0)
->addDataset('mfu_size', 'GAUGE', 0)
->addDataset('p', 'GAUGE', 0)
->addDataset('rec_used_per', 'GAUGE', 0)
->addDataset('freq_used_per', 'GAUGE', 0)
->addDataset('arc_hits', 'DERIVE', 0)
->addDataset('arc_misses', 'DERIVE', 0)
->addDataset('demand_data_hits', 'DERIVE', 0)
->addDataset('demand_data_misses', 'DERIVE', 0)
->addDataset('demand_meta_hits', 'DERIVE', 0)
->addDataset('demand_meta_misses', 'DERIVE', 0)
->addDataset('mfu_ghost_hits', 'DERIVE', 0)
->addDataset('mfu_hits', 'DERIVE', 0)
->addDataset('mru_ghost_hits', 'DERIVE', 0)
->addDataset('mru_hits', 'DERIVE', 0)
->addDataset('pre_data_hits', 'DERIVE', 0)
->addDataset('pre_data_misses', 'DERIVE', 0)
->addDataset('pre_meta_hits', 'DERIVE', 0)
->addDataset('pre_meta_misses', 'DERIVE', 0)
->addDataset('anon_hits', 'DERIVE', 0)
->addDataset('arc_accesses_total', 'DERIVE', 0)
->addDataset('demand_data_total', 'DERIVE', 0)
->addDataset('pre_data_total', 'DERIVE', 0)
->addDataset('real_hits', 'DERIVE', 0)
->addDataset('cache_hits_per', 'GAUGE', 0)
->addDataset('cache_miss_per', 'GAUGE', 0)
->addDataset('actual_hit_per', 'GAUGE', 0)
->addDataset('data_demand_per', 'GAUGE', 0)
->addDataset('data_pre_per', 'GAUGE', 0)
->addDataset('anon_hits_per', 'GAUGE', 0)
->addDataset('mru_per', 'GAUGE', 0)
->addDataset('mfu_per', 'GAUGE', 0)
->addDataset('mru_ghost_per', 'GAUGE', 0)
->addDataset('mfu_ghost_per', 'GAUGE', 0)
->addDataset('demand_hits_per', 'GAUGE', 0)
->addDataset('pre_hits_per', 'GAUGE', 0)
->addDataset('meta_hits_per', 'GAUGE', 0)
->addDataset('pre_meta_hits_per', 'GAUGE', 0)
->addDataset('demand_misses_per', 'GAUGE', 0)
->addDataset('pre_misses_per', 'GAUGE', 0)
->addDataset('meta_misses_per', 'GAUGE', 0)
->addDataset('pre_meta_misses_per', 'GAUGE', 0);
$fields = array(
'deleted' => $zfs{deleted},
'evict_skip' => $zfs{evict_skip},
'mutex_skip' => $zfs{mutex_skip},
'recycle_miss' => $zfs{recycle_miss},
'arc_size' => $zfs{arc_size},
'target_size_max' => $zfs{target_size_max},
'target_size_min' => $zfs{target_size_min},
'target_size' => $zfs{target_size},
'target_size_per' => $zfs{target_size_per},
'arc_size_per' => $zfs{arc_size_per},
'target_size_arat' => $zfs{target_size_arat},
'min_size_per' => $zfs{min_size_per},
'mfu_size' => $zfs{mfu_size},
'p' => $zfs{p},
'rec_used_per' => $zfs{rec_used_per},
'freq_used_per' => $zfs{freq_used_per},
'arc_hits' => $zfs{arc_hits},
'arc_misses' => $zfs{arc_misses},
'demand_data_hits' => $zfs{demand_data_hits},
'demand_data_misses' => $zfs{demand_data_misses},
'demand_meta_hits' => $zfs{demand_meta_hits},
'demand_meta_misses' => $zfs{demand_meta_misses},
'mfu_ghost_hits' => $zfs{mfu_ghost_hits},
'mfu_hits' => $zfs{mfu_hits},
'mru_ghost_hits' => $zfs{mru_ghost_hits},
'mru_hits' => $zfs{mru_hits},
'pre_data_hits' => $zfs{pre_data_hits},
'pre_data_misses' => $zfs{pre_data_misses},
'pre_meta_hits' => $zfs{pre_meta_hits},
'pre_meta_misses' => $zfs{pre_meta_misses},
'anon_hits' => $zfs{anon_hits},
'arc_accesses_total' => $zfs{arc_accesses_total},
'demand_data_total' => $zfs{demand_data_total},
'pre_data_total' => $zfs{pre_data_total},
'real_hits' => $zfs{real_hits},
'cache_hits_per' => $zfs{cache_hits_per},
'cache_miss_per' => $zfs{cache_miss_per},
'actual_hit_per' => $zfs{actual_hit_per},
'data_demand_per' => $zfs{data_demand_per},
'data_pre_per' => $zfs{data_pre_per},
'anon_hits_per' => $zfs{anon_hits_per},
'mru_per' => $zfs{mru_per},
'mfu_per' => $zfs{mfu_per},
'mru_ghost_per' => $zfs{mru_ghost_per},
'mfu_ghost_per' => $zfs{mfu_ghost_per},
'demand_hits_per' => $zfs{demand_hits_per},
'pre_hits_per' => $zfs{pre_hits_per},
'meta_hits_per' => $zfs{meta_hits_per},
'pre_meta_hits_per' => $zfs{pre_meta_hits_per},
'demand_misses_per' => $zfs{demand_misses_per},
'pre_misses_per' => $zfs{pre_misses_per},
'meta_misses_per' => $zfs{meta_misses_per},
'pre_meta_misses_per' => $zfs{pre_meta_misses_per},
);
$tags = array('name' => $name, 'app_id' => $app_id, 'rrd_def' => $rrd_def, 'rrd_name' => $rrd_name);
data_update($device, 'app', $tags, $fields);
//
// process additional info returned
//
$pools=array();
$pool_rrd_def = RrdDefinition::make()
->addDataset('size', 'GAUGE', 0)
->addDataset('alloc', 'GAUGE', 0)
->addDataset('free', 'GAUGE', 0)
->addDataset('expandsz', 'GAUGE', 0)
->addDataset('frag', 'GAUGE', 0)
->addDataset('cap', 'GAUGE', 0)
->addDataset('dedup', 'GAUGE', 0);
$pools_int=0;
while (isset($zfs{'pools'}{$pools_int})) {
$pools[]=$zfs{'pools'}{$pools_int}{'name'};
$rrd_name = array('app', $name, $app_id, $zfs{'pools'}{$pools_int}{'name'});
$fields = array(
'size' => $zfs{'pools'}{$pools_int}{'size'},
'alloc' => $zfs{'pools'}{$pools_int}{'alloc'},
'free' => $zfs{'pools'}{$pools_int}{'free'},
'expandsz' => $zfs{'pools'}{$pools_int}{'expandsz'},
'frag' => $zfs{'pools'}{$pools_int}{'frag'},
'cap' => $zfs{'pools'}{$pools_int}{'cap'},
'dedup' => $zfs{'pools'}{$pools_int}{'dedup'},
);
$tags = array('name' => $name, 'app_id' => $app_id, 'rrd_def' => $pool_rrd_def, 'rrd_name' => $rrd_name);
data_update($device, 'app', $tags, $fields);
$pools_int++;
}
//
// component processing for ZFS
//
$device_id=$device['device_id'];
$options=array(
'filter' => array(
'device_id' => array('=', $device_id),
'type' => array('=', 'zfs'),
),
);
$component=new LibreNMS\Component();
$components=$component->getComponents($device_id, $options);
// if no pools, delete zfs components
if (empty($pools)) {
if (isset($components[$device_id])) {
foreach ($components[$device_id] as $component_id => $_unused) {
$component->deleteComponent($component_id);
}
}
} else {
if (isset($components[$device_id])) {
$zfsc = $components[$device_id];
} else {
$zfsc = $component->createComponent($device_id, 'zfs');
}
$id = $component->getFirstComponentID($zfsc);
$zfsc[$id]['label'] = 'ZFS';
$zfsc[$id]['pools'] = json_encode($pools);
$component->setComponentPrefs($device_id, $zfsc);
}