#!/usr/bin/perl -w
###############################################################################
# Webmin Sysstats - ups-lib.pl
#
# Webmin Sysstats Module
# Copyright (C) 2003 by Eric Gerbier
# Bug reports to: gerbier@users.sourceforge.net
# $Id$
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
###############################################################################
use strict;
use warnings;
use English qw(-no_match_vars);
unset_warnings();
require RRDs;
set_warnings();
# from web-lib.pl
## no critic(ProhibitPackageVars)
use vars qw(%config %text %in $in $cb $tb %access );
## use critic
my $fscript = 'ups.pl';
my $pre = 'vol';
my $EMPTY = EMPTY();
my $COMMA = COMMA();
###############################################################################
sub install_module($$) {
my ( $minfo, $defaults ) = ( $_[0], $_[1] );
debug_sub_begin();
my %my_config = init_module_config( 'ups', 1 );
$my_config{'sample_rate'} = 2;
$my_config{'keep'} = 1; # manual
$my_config{'graph_type'} = 0;
# test for ups binary
$my_config{'upsc'} = guess_ups_command();
if ( is_upsc( $my_config{'upsc'} ) ) {
# first disable module : will have to configure it
$my_config{'runstop'} = 1;
$my_config{'server'} = $EMPTY;
}
else {
# apcaccess is ready to start
$my_config{'runstop'} = 0;
$my_config{'server'} = 'status';
}
write_config( $minfo, \%my_config );
install_script( $minfo, $fscript );
debug_sub_end();
return 1;
}
###############################################################################
sub graph_data($$) {
my ( $minfo, $my_config ) = ( $_[0], $_[1] );
debug_sub_begin();
my $cf = $my_config->{'cf'};
# take care of cgi parameters
my ( $graph_type, $c_display ) = get_cgi_graph($my_config);
my @rrd_detals;
gprint_title( 'ups', 'Parameters', \@rrd_detals );
my $vol_num = 1;
my $first_graph = 1;
VOL: while ( defined $my_config->{ $pre . $vol_num } ) {
my $vol_nb = 'total' . $vol_num;
my ( $vol_id, $vol_name, $vol_config, $runstop, $display ) =
split /,/, $my_config->{ $pre . $vol_num };
if ($runstop) {
$vol_num++;
next VOL;
}
if ( $display == $c_display ) {
add_def( \@rrd_detals, $vol_nb, $minfo->{'dbtables'} . $vol_id,
'total', $cf );
if ( $graph_type == 0 ) {
# histograms
my $type;
if ($first_graph) {
$first_graph = 0;
$type = 'AREA';
}
else {
$type = 'STACK';
}
gprint_param( \@rrd_detals, $vol_nb, $vol_name, $vol_config,
$type );
}
else {
# line
gprint_param( \@rrd_detals, $vol_nb, $vol_name, $vol_config );
}
}
$vol_num++;
}
graph_common( $minfo, $my_config, @rrd_detals );
debug_sub_end();
return;
}
###############################################################################
sub mod_config($$$) {
my ( $minfo, $my_config, $defaults ) = ( $_[0], $_[1], $_[2] );
debug_sub_begin();
mod_config_opt( $minfo, $my_config, $pre );
begin_html_config(1);
# title general
change_database( $minfo, $my_config );
change_local_params($my_config);
change_display($my_config);
change_scale( $minfo, $my_config );
change_module_config($my_config);
change_default( $my_config->{'graph_type'} );
my @columns = (
'module_subtitle_vol_name', 'word_subtitle_disp_colour',
'word_subtitle_controls',
);
end_html_config(@columns);
my $vol_num = 1;
while ( defined $my_config->{ $pre . $vol_num } ) {
my ( $vol_id, $vol_name, $vol_config, $runstop, $display ) =
split /,/, $my_config->{ $pre . $vol_num };
my ( $vol_colour, $vol_line ) = get_line_config($vol_config);
print "<tr $cb>";
# name
print
"<td><strong><a href=\"edit_module.cgi?idx=$in{'idx'}&opt=edit&vol_num=$vol_num\">$vol_name</a></strong></td>";
# color
print "<td><font color=\"#$vol_colour\"><strong>";
print $text{ 'colour_' . $vol_colour }
? $text{ 'colour_' . $vol_colour }
: "<pre>#$vol_colour </pre>";
print "</strong></font></td>\n";
# controls
print '<td align=right>';
display_parameter_line( $vol_num, $runstop, $display, $my_config,
$pre );
print "</td>\n";
$vol_num++;
}
print "</tr>\n";
print "</table></td></tr>\n"; # configuration
if ( ( exists $in{'opt'} ) and ( $in{'opt'} eq 'edit' ) ) {
my ( $vol_id, $vol_name, $vol_config, $runstop, $display ) =
split /,/, $my_config->{ $pre . $in{'vol_num'} };
my ( $vol_colour, $vol_line ) = get_line_config($vol_config);
begin_table( 'edition', 'border' );
print "<tr $tb>";
title_row( $text{'module_vol'} );
print '</tr>';
print "<tr $cb>";
print '<td>';
print '<form action="save_config.cgi">';
print '<table ' . w100() . ">\n"; # table form
print "<tr>\n";
title_row( $text{'module_word_vol'}, w15() );
print '<td nowrap ' . width(5) . ">$vol_name</td>";
#title_row( $vol_name, "nowrap width=\"5%\"" );
#print "<td>($tab{$vol_name})</td>";
print "</tr>\n";
modify_colour( $vol_config, $display, $runstop, $my_config, $pre );
print '<tr>';
print '<td align=left>';
print '<input type=hidden name=idx value="' . $in{'idx'} . '">';
print '<input type=hidden name=opt value="update_vol">';
print '<input type=hidden name=vol value="' . $in{'vol_num'} . '\">';
print "<input type=submit value=\"$text{'word_update'}\">";
print "</td>\n";
print "</tr>\n";
print "</table>\n"; # end table form
print "</form>\n";
print "</td>\n";
print "</tr>\n";
end_table(); # end table edition
}
else {
my $i = 0;
begin_table( 'new_config', 'border' );
print "<tr $tb>";
title_row( $text{'module_new_vol'} );
print "</tr><tr $cb>";
print '<td>';
print '<form action="save_config.cgi">';
print '<table ' . w100() . ">\n"; # form
print "<tr>\n";
title_row( $text{'module_word_vol'}, w15() );
print '<td nowrap><strong>';
print "<select name=\"new_vol_def\">\n";
print '<option value="' . $i++ . "\">$text{'word_select'}\n";
my @tab = filter_known( $my_config, tab_param_ups($my_config) );
foreach my $vlist (@tab) {
print '<option value="' . $i++ . "\">$vlist\n";
}
print '</select>';
print '</strong></td>';
print "</tr>\n";
modify_colour( '00ff00', 0, 0, $my_config, $pre );
print '<tr>';
print '<td align=left>';
print '<input type=hidden name=idx value="' . $in{'idx'} . '">';
print '<input type=hidden name=opt value="new_vol">';
print '<input type=hidden name=vol value="' . $vol_num . '">';
print "<input type=submit value=\"$text{'word_addnew'}\">";
print "</td>\n";
print "</tr>\n";
print "</table>\n"; # form
print "</form>\n";
print "</td>\n";
print "</tr>\n";
end_table(); # new_config
}
end_table(); # colors
print "</table>\n"; # top
debug_sub_end();
return;
}
###############################################################################
sub mod_config_save($$$) {
my ( $minfo, $my_config, $defaults ) = ( $_[0], $_[1], $_[2] );
debug_sub_begin();
if ( $in{'opt'} eq 'new_vol' ) {
if (
( $in{'new_vol_def'} eq '0' )
or ( ( $in{'vol_colour1_def'} eq 'nocolour' )
and ( $in{'vol_colour2_def'} eq $EMPTY ) )
)
{
error( $text{'save_einvaled_selection'} );
}
my @tab = filter_known( $my_config, tab_param_ups($my_config) );
my $new_vol = @tab[ $in{'new_vol_def'} - 1 ];
create_base_ups( $minfo, $my_config, $my_config->{'db_uid'} );
$my_config->{ $pre . $in{$pre} } = join $COMMA,
$my_config->{'db_uid'}++, $new_vol,
set_line_config( get_colourselect( 'vol_colour', $EMPTY ),
get_lineselect('vol_line') ),
0,
$in{'display_def'};
write_config( $minfo, $my_config );
myredirect("edit_module.cgi?idx=$in{'idx'}");
}
elsif ( $in{'opt'} eq 'update_vol' ) {
if ( ( $in{'vol_colour1_def'} eq 'nocolour' )
and ( $in{'vol_colour2_def'} eq $EMPTY ) )
{
error( $text{'save_einvaled_selection'} );
}
my ( $vol_id, $vol_name, $vol_colour, $runstop, $display ) =
split /,/, $my_config->{ $pre . $in{$pre} };
$my_config->{ $pre . $in{$pre} } = join $COMMA, $vol_id, $vol_name,
set_line_config( get_colourselect( 'vol_colour', $EMPTY ),
get_lineselect('vol_line') ),
$in{'runstop_def'},
$in{'display_def'};
# test for display : force to create an dummy label
test_for_new_display($my_config);
write_config( $minfo, $my_config );
myredirect("edit_module.cgi?idx=$in{'idx'}");
}
elsif ( $in{'opt'} eq 'general' ) {
test_database_change( $minfo, $my_config );
test_local_params($my_config);
test_display_change($my_config);
test_scale_change( $minfo, $my_config );
test_default_change($my_config);
test_module_config($my_config);
write_config( $minfo, $my_config );
}
else {
error($in);
}
debug_sub_end();
return;
}
###############################################################################
sub create_base_ups($$$) {
my ( $minfo, $my_config, $db_uid ) = ( $_[0], $_[1], $_[2] );
debug_sub_begin();
my $cf = $my_config->{'cf'};
my $heartbeat = compute_heartbeat( $my_config->{'sample_rate'} );
my $base = $minfo->{'dbtables'} . $db_uid . '.rrd';
my $type = 'GAUGE';
create_rrd( $base, "DS:total:$type:$heartbeat:0:U", $cf );
debug_sub_end();
return;
}
###############################################################################
sub write_config($$) {
my ( $minfo, $my_config ) = ( $_[0], $_[1] );
debug_sub_begin();
common_write_config( $minfo, $my_config );
debug_sub_end();
return;
}
###############################################################################
sub upgrade($$$) {
my ( $minfo, $my_config, $defaults ) = ( $_[0], $_[1], $_[2] );
debug_sub_begin();
# we have to fix bug : with previous release the first database is 0.rrd
# it should be 1.rrd (bad db_uid)
my $test_db = $minfo->{'dbtables'} . '0.rrd';
if ( -f $test_db ) {
# build list of databases
my @liste_rrd = get_rrd_names($minfo);
my %id;
debug("@liste_rrd");
foreach my $base (@liste_rrd) {
my $basename = basename( $base, '.rrd' );
debug("found database $basename ($base)");
$id{$basename} = 1;
}
# we have to change (+1) all volumes in config, and rename databases
# sorted list of databases
my @sorted_list_id = reverse sort { $a <=> $b } keys %id;
foreach my $id (@sorted_list_id) {
# rename database
my $new_id = $id + 1;
my $old_db = $minfo->{'dbtables'} . $id . '.rrd';
if ( !-f $old_db ) {
warning("can not find $old_db database");
next;
}
my $new_db = $minfo->{'dbtables'} . $new_id . '.rrd';
if ( -f $new_db ) {
warning("find unwanted $old_db database");
next;
}
else {
rename $old_db, $new_db;
debug("rename $old_db into $new_db");
}
}
# change config
foreach my $key ( keys %{$my_config} ) {
debug("config key $key");
my $vol = is_vol( $key, $my_config->{$key} );
if ( defined $vol ) {
my @tab = split /,/, $my_config->{$key};
$tab[0] = $vol + 1;
$my_config->{$key} = join $COMMA, @tab;
debug("change vol : $key ($vol)");
}
else {
debug('not a vol');
}
}
write_config( $minfo, $my_config );
}
debug_sub_end();
return;
}
###############################################################################
sub tab_param_ups($) {
my $my_config = shift @_;
my @tab;
if ( $my_config->{'upsc'} ) {
# get list from ups command
my $r_tab = read_pipe("$my_config->{'upsc'} $my_config->{'server'}");
if ( defined $r_tab ) {
foreach ( @{$r_tab} ) {
if (m/^(.*):\s+[+-]?\d+\.?\d*/) {
push @tab, $1;
}
}
}
}
else {
warning('ups command not found');
}
return @tab;
}
###############################################################################
# get/set_display/runstop must be defined to allow mod_config_opt to work
sub toggle_display($) {
my $line = shift @_;
my ( $vol_id, $vol_name, $vol_config, $runstop, $display ) =
unpack_config($line);
$display = toggle_param_display($display);
$line = pack_config( $vol_id, $vol_name, $vol_config, $runstop, $display );
return $line;
}
###############################################################################
sub toggle_runstop($) {
my $line = shift @_;
my ( $vol_id, $vol_name, $vol_config, $runstop, $display ) =
unpack_config($line);
$runstop = toggle_param_runstop($runstop);
$line = pack_config( $vol_id, $vol_name, $vol_config, $runstop, $display );
return $line;
}
###############################################################################
# local config
###############################################################################
sub change_module_config($) {
my $my_config = $_[0];
debug_sub_begin();
titre_table('configuration');
begin_table('configuration');
# command
print '<tr>';
title_row('upscmd');
print '<td ' . width(35) . '>';
print
"<input type=text name=\"ups_cmd\" size=24 maxlength=48 value=\"$my_config->{'upsc'}\">";
print wrapper( 'file_chooser_button', 'ups_cmd', 0 );
print '</td>';
print '</tr>';
# server
if ( is_upsc( $my_config->{'upsc'} ) ) {
print '<tr>';
title_row('upsname');
print '<td ' . width(35) . '>';
print
"<input type=text name=\"server\" size=24 maxlength=48 value=\"$my_config->{'server'}\">";
print '</td>';
print '</tr>';
}
end_table(); # config
separator();
debug_sub_end();
return;
}
###############################################################################
sub test_module_config($) {
my $my_config = $_[0];
debug_sub_begin();
$my_config->{'upsc'} = $in{'ups_cmd'};
$my_config->{'runstop'} = test_command( $my_config->{'upsc'} );
if ( $my_config->{'runstop'} ) {
warning( 'disable ups : ' . get_error() );
}
elsif ( is_upsc( $in{'ups_cmd'} ) ) {
$my_config->{'server'} = $in{'server'};
if ( $my_config->{'server'} ) {
$my_config->{'runstop'} = 0;
# we need to create now databases
# todo
}
else {
$my_config->{'runstop'} = 1;
}
}
else {
# dummy server : just to keep same command in ups.pl
$my_config->{'server'} = 'status';
}
debug_sub_end();
return;
}
###############################################################################
sub guess_ups_command() {
my $cmd;
foreach my $try ( 'upsc', 'apcaccess' ) {
$cmd = search_command($try);
last if ($cmd);
}
return $cmd;
}
###############################################################################
sub is_upsc($) {
my $cmd = shift @_;
return ( ( !$cmd ) || ( $cmd =~ m/upsc/ ) );
}
###############################################################################
1;