Skip to content

Commit 72ce39c

Browse files
murrantlaf
authored andcommitted
refactor: schema updates (librenms#6370)
Test the schema files with STRICT_TRANS_TABLES and fix any issues
1 parent c5c643f commit 72ce39c

20 files changed

+96
-87
lines changed

includes/common.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,7 @@ function version_info($remote = true)
11031103
$output['local_date'] = $local_date;
11041104
$output['local_branch'] = rtrim(`git rev-parse --abbrev-ref HEAD`);
11051105
}
1106-
$output['db_schema'] = dbFetchCell('SELECT version FROM dbSchema');
1106+
$output['db_schema'] = get_db_schema();
11071107
$output['php_ver'] = phpversion();
11081108
$output['mysql_ver'] = dbFetchCell('SELECT version()');
11091109
$output['rrdtool_ver'] = implode(' ', array_slice(explode(' ', shell_exec($config['rrdtool'].' --version |head -n1')), 1, 1));

includes/functions.php

+46
Original file line numberDiff line numberDiff line change
@@ -2267,3 +2267,49 @@ function index_schema_to_sql($index_data)
22672267

22682268
return sprintf($index, $columns);
22692269
}
2270+
2271+
/**
2272+
* Get an array of the schema files.
2273+
* schema_version => full_file_name
2274+
*
2275+
* @return mixed
2276+
*/
2277+
function get_schema_list()
2278+
{
2279+
global $config;
2280+
2281+
// glob returns an array sorted by filename
2282+
$files = glob($config['install_dir'].'/sql-schema/*.sql');
2283+
2284+
// set the keys to the db schema version
2285+
return array_reduce($files, function ($array, $file) {
2286+
$array[basename($file, '.sql')] = $file;
2287+
return $array;
2288+
}, array());
2289+
}
2290+
2291+
/**
2292+
* Get the current database schema, will return 0 if there is no schema.
2293+
*
2294+
* @return int
2295+
*/
2296+
function get_db_schema()
2297+
{
2298+
return (int)@dbFetchCell('SELECT version FROM `dbSchema` ORDER BY version DESC LIMIT 1');
2299+
}
2300+
2301+
/**
2302+
* Check if the database schema is up to date.
2303+
*
2304+
* @return bool
2305+
*/
2306+
function db_schema_is_current()
2307+
{
2308+
$current = get_db_schema();
2309+
2310+
$schemas = get_schema_list();
2311+
end($schemas);
2312+
$latest = key($schemas);
2313+
2314+
return $current >= $latest;
2315+
}

includes/sql-schema/update.php

+16-52
Original file line numberDiff line numberDiff line change
@@ -21,51 +21,24 @@
2121
require realpath(__DIR__ . '/../..') . '/includes/init.php';
2222

2323
$options = getopt('d');
24-
if (isset($options['d'])) {
25-
$debug = true;
26-
} else {
27-
$debug = false;
28-
}
29-
}
30-
31-
$insert = 0;
32-
33-
if ($db_rev = @dbFetchCell('SELECT version FROM `dbSchema` ORDER BY version DESC LIMIT 1')) {
34-
} else {
35-
$db_rev = 0;
36-
$insert = 1;
37-
}
38-
39-
$updating = 0;
40-
41-
$include_dir_regexp = '/\.sql$/';
42-
43-
if ($handle = opendir($config['install_dir'].'/sql-schema')) {
44-
while (false !== ($file = readdir($handle))) {
45-
if (filetype($config['install_dir'].'/sql-schema/'.$file) == 'file' && preg_match($include_dir_regexp, $file)) {
46-
$filelist[] = $file;
47-
}
48-
}
49-
50-
closedir($handle);
24+
$debug = isset($options['d']);
5125
}
5226

53-
asort($filelist);
54-
$tmp = explode('.', max($filelist), 2);
55-
if ($tmp[0] <= $db_rev) {
56-
if ($debug) {
57-
echo "DB Schema already up to date.\n";
58-
}
27+
if (db_schema_is_current()) {
28+
d_echo("DB Schema already up to date.\n");
5929
return;
6030
}
6131

6232
// Set Database Character set and Collation
6333
dbQuery('ALTER DATABASE ? CHARACTER SET utf8 COLLATE utf8_unicode_ci;', array(array($config['db_name'])));
6434

35+
$db_rev = get_db_schema();
36+
$insert = ($db_rev == 0); // if $db_rev == 0, insert the first update
37+
38+
$updating = 0;
6539
$limit = 150; //magic marker far enough in the future
66-
foreach ($filelist as $file) {
67-
list($filename,$extension) = explode('.', $file, 2);
68-
if ($filename > $db_rev) {
40+
foreach (get_schema_list() as $file_rev => $file) {
41+
if ($file_rev > $db_rev) {
6942
if (isset($_SESSION['stage'])) {
7043
$limit++;
7144
if (time()-$_SESSION['last'] > 45) {
@@ -79,42 +52,33 @@
7952
echo "-- Updating database schema\n";
8053
}
8154

82-
echo sprintf('%03d', $db_rev).' -> '.sprintf('%03d', $filename).' ...';
55+
printf('%03d -> %03d ...', $db_rev, $file_rev);
8356

8457
$err = 0;
85-
86-
if ($fd = @fopen($config['install_dir'].'/sql-schema/'.$file, 'r')) {
87-
$data = fread($fd, 4096);
88-
while (!feof($fd)) {
89-
$data .= fread($fd, 4096);
90-
}
91-
58+
if ($data = file_get_contents($file)) {
9259
foreach (explode("\n", $data) as $line) {
9360
if (trim($line)) {
9461
d_echo("$line \n");
9562

9663
if ($line[0] != '#') {
97-
$update = mysqli_query($database_link, $line);
98-
if (!$update) {
64+
if (!mysqli_query($database_link, $line)) {
9965
$err++;
100-
if ($debug) {
101-
echo mysqli_error($database_link)."\n";
102-
}
66+
d_echo(mysqli_error($database_link) . PHP_EOL);
10367
}
10468
}
10569
}
10670
}
10771

10872
echo " done ($err errors).\n";
10973
} else {
110-
echo " Could not open file!\n";
74+
echo " Could not open file! $file\n";
11175
}//end if
11276

11377
$updating++;
114-
$db_rev = $filename;
78+
$db_rev = $file_rev;
11579
if ($insert) {
11680
dbInsert(array('version' => $db_rev), 'dbSchema');
117-
$insert = 0;
81+
$insert = false;
11882
} else {
11983
dbUpdate(array('version' => $db_rev), 'dbSchema');
12084
}

poll-billing.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
echo "Starting Polling Session ... \n\n";
2424

2525
// Wait for schema update, as running during update can break update
26-
$dbVersion = dbFetchCell('SELECT version FROM dbSchema');
26+
$dbVersion = get_db_schema();
2727
if ($dbVersion < 107) {
28-
logfile("BILLING: Cannot continue until dbSchema update to >= 107 is complete");
28+
logfile("BILLING: Cannot continue until the database schema update to >= 107 is complete");
2929
exit(1);
3030
}
3131

sql-schema/055.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.sensor','(%sensors.sensor_alert = 1)','(%sensors.sensor_alert = 1)','Sensors of interest','alerting',0,'macros',0,1,0);
1+
insert into `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) values ('alert.macros.rule.sensor','(%sensors.sensor_alert = 1)','(%sensors.sensor_alert = 1)','Sensors of interest','alerting',0,'macros',0,'1','0')

sql-schema/056.sql

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CREATE TABLE IF NOT EXISTS `device_perf` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `timestamp` datetime NOT NULL, `xmt` float NOT NULL, `rcv` float NOT NULL, `loss` float NOT NULL, `min` float NOT NULL, `max` float NOT NULL, `avg` float NOT NULL, KEY `id` (`id`,`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
2-
insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_15m','(%macros.past_15m && %device_perf.loss)','(%macros.past_15m && %device_perf.loss)','Packet loss over the last 15 minutes','alerting',0,'macros',0,1,0);
3-
insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_5m','(%macros.past_5m && %device_perf.loss)','(%macros.past_5m && %device_perf.loss)','Packet loss over the last 5 minutes','alerting',0,'macros',0,1,0);
2+
insert into config (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) values ('alert.macros.rule.packet_loss_15m','(%macros.past_15m && %device_perf.loss)','(%macros.past_15m && %device_perf.loss)','Packet loss over the last 15 minutes','alerting',0,'macros',0,'1','0');
3+
insert into config (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) values ('alert.macros.rule.packet_loss_5m','(%macros.past_5m && %device_perf.loss)','(%macros.past_5m && %device_perf.loss)','Packet loss over the last 5 minutes','alerting',0,'macros',0,'1','0');
44
ALTER TABLE `devices` ADD `status_reason` VARCHAR( 50 ) NOT NULL AFTER `status` ;
55
UPDATE `devices` SET `status_reason`='down' WHERE `status`=0;

sql-schema/073.sql

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
INSERT INTO `graph_types`(`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES ('device', 'pulse_users', 'firewall', 'Active Users', '');
2-
INSERT INTO `graph_types`(`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES ('device', 'pulse_sessions', 'firewall', 'Active Sessions', '');
1+
INSERT INTO `graph_types`(`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES ('device', 'pulse_users', 'firewall', 'Active Users', 0);
2+
INSERT INTO `graph_types`(`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES ('device', 'pulse_sessions', 'firewall', 'Active Sessions', 0);

sql-schema/110.sql

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
INSERT INTO config VALUES ('','alert.transports.canopsis.user','','','Canopsis User','alerting',0, 'transports', 0, 0, 0);
2-
INSERT INTO config VALUES ('','alert.transports.canopsis.passwd','','','Canopsis Password','alerting',0, 'transports', 0, 0, 0);
3-
INSERT INTO config VALUES ('','alert.transports.canopsis.host','','','Canopsis Hostname','alerting',0, 'transports', 0, 0, 0);
4-
INSERT INTO config VALUES ('','alert.transports.canopsis.vhost','','','Canopsis vHost','alerting',0, 'transports', 0, 0, 0);
1+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.transports.canopsis.user','','','Canopsis User','alerting',0, 'transports', 0, '0', '0');
2+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.transports.canopsis.passwd','','','Canopsis Password','alerting',0, 'transports', 0, '0', '0');
3+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.transports.canopsis.host','','','Canopsis Hostname','alerting',0, 'transports', 0, '0', '0');
4+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.transports.canopsis.vhost','','','Canopsis vHost','alerting',0, 'transports', 0, '0', '0');

sql-schema/111.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
INSERT INTO config VALUES ('','alert.transports.canopsis.port','','','Canopsis Port number','alerting',0, 'transports', 0, 0, 0);
1+
INSERT INTO config (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.transports.canopsis.port','','','Canopsis Port number','alerting',0, 'transports', 0, '0', '0');

sql-schema/113.sql

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
CREATE TABLE IF NOT EXISTS `route` ( `device_id` int(11) NOT NULL, `context_name` varchar(128) CHARACTER SET utf8 collate utf8_general_ci not null, `ipRouteDest` varchar(256) not null, `ipRouteIfIndex` varchar(256), `ipRouteMetric` varchar(256) not null, `ipRouteNextHop` varchar(256) not null, `ipRouteType` varchar(256) not null, `ipRouteProto` varchar(256) not null, `discoveredAt` int(11) NOT NULL, `ipRouteMask` varchar(256) not null ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2-
ALTER TABLE `route` ADD INDEX `device` (`device_id` ASC, `context_name` ASC, `ipRouteDest`(255) ASC, `ipRouteNextHop` ASC);
1+
CREATE TABLE IF NOT EXISTS `route` ( `device_id` int(11) NOT NULL, `context_name` varchar(128) CHARACTER SET utf8 collate utf8_general_ci not null, `ipRouteDest` varchar(256) not null, `ipRouteIfIndex` varchar(256), `ipRouteMetric` varchar(256) not null, `ipRouteNextHop` varchar(256) not null, `ipRouteType` varchar(256) not null, `ipRouteProto` varchar(256) not null, `discoveredAt` int(11) NOT NULL, `ipRouteMask` varchar(256) not null, INDEX `device` (`device_id` ASC, `context_name` ASC, `ipRouteDest`(255) ASC, `ipRouteNextHop` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

sql-schema/123.sql

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
INSERT INTO `config` (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) VALUES ('alert.macros.rule.port_in_usage_perc','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','Ports using more than X perc of capacity IN','alerting',0,'macros',0,1,0);
2-
INSERT INTO `config` (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) VALUES ('alert.macros.rule.port_out_usage_perc','((%ports.ifOutOctets_rate*8)/%ports.ifSpeed)*100','((%ports.ifOutOctets_rate*8)/%ports.ifSpeed)*100','Ports using more than X perc of capacity OUT','alerting',0,'macros',0,1,0);
3-
INSERT INTO `config` (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) VALUES ('alert.macros.rule.port_now_down','%ports.ifOperStatus != %ports.ifOperStatus_prev && %ports.ifOperStatus_prev = "up" && %ports.ifAdminStatus = "up"','%ports.ifOperStatus != %ports.ifOperStatus_prev && %ports.ifOperStatus_prev = "up" && %ports.ifAdminStatus = "up"','Port has gone down','alerting',0,'macros',0,1,0);
4-
INSERT INTO `config` (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) VALUES ('alert.macros.rule.device_component_down_junos','%sensors.sensor_class = "state" && %sensors.sensor_current != "6" && %sensors.sensor_type = "jnxFruState" && %sensors.sensor_current != "2"','%sensors.sensor_class = "state" && %sensors.sensor_current != "6" && %sensors.sensor_type = "jnxFruState" && %sensors.sensor_current != "2"','Device Component down [JunOS]','alerting',0,'macros',0,1,0);
5-
INSERT INTO `config` (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) VALUES ('alert.macros.rule.device_component_down_cisco','%sensors.sensor_current != "1" && %sensors.sensor_current != "5" && %sensors.sensor_type ~ "^cisco.*State$"','%sensors.sensor_current != "1" && %sensors.sensor_current != "5" && %sensors.sensor_type ~ "^cisco.*State$"','Device Component down [Cisco]','alerting',0,'macros',0,1,0);
6-
INSERT INTO `config` (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) VALUES ('alert.macros.rule.pdu_over_amperage_apc','%sensors.sensor_class = "current" && %sensors.sensor_descr = "Bank Total" && %sensors.sensor_current > %sensors.sensor_limit && %devices.os = "apc"','%sensors.sensor_class = "current" && %sensors.sensor_descr = "Bank Total" && %sensors.sensor_current > %sensors.sensor_limit && %devices.os = "apc"','PDU Over Amperage [APC]','alerting',0,'macros',0,1,0);
1+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.macros.rule.port_in_usage_perc','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','Ports using more than X perc of capacity IN','alerting',0,'macros',0,'1','0');
2+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.macros.rule.port_out_usage_perc','((%ports.ifOutOctets_rate*8)/%ports.ifSpeed)*100','((%ports.ifOutOctets_rate*8)/%ports.ifSpeed)*100','Ports using more than X perc of capacity OUT','alerting',0,'macros',0,'1','0');
3+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.macros.rule.port_now_down','%ports.ifOperStatus != %ports.ifOperStatus_prev && %ports.ifOperStatus_prev = "up" && %ports.ifAdminStatus = "up"','%ports.ifOperStatus != %ports.ifOperStatus_prev && %ports.ifOperStatus_prev = "up" && %ports.ifAdminStatus = "up"','Port has gone down','alerting',0,'macros',0,'1','0');
4+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.macros.rule.device_component_down_junos','%sensors.sensor_class = "state" && %sensors.sensor_current != "6" && %sensors.sensor_type = "jnxFruState" && %sensors.sensor_current != "2"','%sensors.sensor_class = "state" && %sensors.sensor_current != "6" && %sensors.sensor_type = "jnxFruState" && %sensors.sensor_current != "2"','Device Component down [JunOS]','alerting',0,'macros',0,'1','0');
5+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.macros.rule.device_component_down_cisco','%sensors.sensor_current != "1" && %sensors.sensor_current != "5" && %sensors.sensor_type ~ "^cisco.*State$"','%sensors.sensor_current != "1" && %sensors.sensor_current != "5" && %sensors.sensor_type ~ "^cisco.*State$"','Device Component down [Cisco]','alerting',0,'macros',0,'1','0');
6+
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.macros.rule.pdu_over_amperage_apc','%sensors.sensor_class = "current" && %sensors.sensor_descr = "Bank Total" && %sensors.sensor_current > %sensors.sensor_limit && %devices.os = "apc"','%sensors.sensor_class = "current" && %sensors.sensor_descr = "Bank Total" && %sensors.sensor_current > %sensors.sensor_limit && %devices.os = "apc"','PDU Over Amperage [APC]','alerting',0,'macros',0,'1','0');
77
INSERT INTO `alert_templates` (`rule_id`, `name`, `template`, `title`, `title_rec`) VALUES (',','BGP Sessions.','%title\\r\\n\nSeverity: %severity\\r\\n\n{if %state == 0}Time elapsed: %elapsed\\r\\n{/if}\nTimestamp: %timestamp\\r\\n\nUnique-ID: %uid\\r\\n\nRule: {if %name}%name{else}%rule{/if}\\r\\n\n{if %faults}Faults:\\r\\n\n{foreach %faults}\n#%key: %value.string\\r\\n\nPeer: %value.astext\\r\\n\nPeer IP: %value.bgpPeerIdentifier\\r\\n\nPeer AS: %value.bgpPeerRemoteAs\\r\\n\nPeer EstTime: %value.bgpPeerFsmEstablishedTime\\r\\n\nPeer State: %value.bgpPeerState\\r\\n\n{/foreach}\n{/if}','','');
88
INSERT INTO `alert_templates` (`rule_id`, `name`, `template`, `title`, `title_rec`) VALUES (',','Ports','%title\\r\\n\nSeverity: %severity\\r\\n\n{if %state == 0}Time elapsed: %elapsed{/if}\nTimestamp: %timestamp\nUnique-ID: %uid\nRule: {if %name}%name{else}%rule{/if}\\r\\n\n{if %faults}Faults:\\r\\n\n{foreach %faults}\\r\\n\n#%key: %value.string\\r\\n\nPort: %value.ifName\\r\\n\nPort Name: %value.ifAlias\\r\\n\nPort Status: %value.message\\r\\n\n{/foreach}\\r\\n\n{/if}\n','','');
99
INSERT INTO `alert_templates` (`rule_id`, `name`, `template`, `title`, `title_rec`) VALUES (',','Temperature','%title\\r\\n\nSeverity: %severity\\r\\n\n{if %state == 0}Time elapsed: %elapsed{/if}\\r\\n\nTimestamp: %timestamp\\r\\n\nUnique-ID: %uid\\r\\n\nRule: {if %name}%name{else}%rule{/if}\\r\\n\n{if %faults}Faults:\\r\\n\n{foreach %faults}\\r\\n\n#%key: %value.string\\r\\n\nTemperature: %value.sensor_current\\r\\n\nPrevious Measurement: %value.sensor_prev\\r\\n\n{/foreach}\\r\\n\n{/if}','','');

0 commit comments

Comments
 (0)