PVE-mods/src/modules/node_info/files/Collector/Ups.pm
Meliox 6585849459
Restructure repo (#251)
* refactor: restructure src/ into modules/, scripts/, and build/

- src/nag_screen/ and src/node_info/ -> src/modules/  (mods grouped explicitly)
- src/Scripts/ -> src/scripts/                        (lowercase, consistent)
- src/gen-rules.sh -> build/                          (build tool separated from source)

Update all references: debian/rules, .github/workflows/*, build/gen-rules.sh,
src/scripts/test/test-syntax.sh (SRC_DIR now points to src/modules/),
src/scripts/test/test-patches.sh, and files.list comments.

* refactor: move CI test scripts from src/scripts/test/ to build/test/

Test scripts are not installed — they are CI/dev tooling and belong
alongside build/gen-rules.sh. Update workflow references and fix the
SRC_DIR path depth in build/test/test-syntax.sh (../ -> ../..).

* d

---------

Co-authored-by: Meliox <na>
2026-08-08 23:46:46 +02:00

126 lines
3.6 KiB
Perl

package PVE::PVEMod::Collector::Ups;
use strict;
use warnings;
use Exporter 'import';
use JSON;
use PVE::PVEMod::Config qw(%config $process_type $ups_state_file);
use PVE::PVEMod::Utils qw(debug setup_collector_signals);
our @EXPORT_OK = qw(
collector_for_ups
);
# ============================================================================
# UPS — long-running collector
# ============================================================================
sub collector_for_ups {
my ($device) = @_;
$process_type = 'collector';
$0 = "collector-ups-$device->{ups_name}";
debug(__LINE__, "UPS collector started");
my $shutdown = 0;
setup_collector_signals("ups-$device->{ups_name}", \$shutdown);
while (!$shutdown) {
my $ups_data = _get_ups_status($device->{ups_name});
eval {
open my $ofh, '>', $ups_state_file
or die "Failed to open $ups_state_file: $!";
print $ofh $ups_data;
close $ofh;
debug(__LINE__, "Wrote UPS data to $ups_state_file");
};
if ($@) {
debug(__LINE__, "Error writing UPS data: $@");
}
sleep $config{intervals}{data_pull} unless $shutdown;
}
debug(__LINE__, "UPS collector shutting down");
exit 0;
}
# ============================================================================
# UPS — status query
# ============================================================================
sub _get_ups_status {
my ($ups_name) = @_;
debug(__LINE__, "Collecting UPS status for $ups_name");
my $output;
if ($config{debug}{ups_mode} && -f $config{debug}{ups_output_file}) {
debug(__LINE__, "Debug mode: reading UPS data from $config{debug}{ups_output_file}");
open my $fh, '<', $config{debug}{ups_output_file}
or do { debug(__LINE__, "Failed to open debug file $config{debug}{ups_output_file}: $!"); return encode_json({ error => "Failed to open debug file" }); };
local $/;
$output = <$fh>;
close $fh;
} else {
$output = `/usr/bin/upsc $ups_name 2>/dev/null`;
}
unless (defined $output && length($output) > 0) {
debug(__LINE__, "No output from upsc for $ups_name");
return encode_json({ error => "No data from UPS $ups_name" });
}
my $ups_data = _parse_upsc_output($output);
unless (keys %$ups_data) {
debug(__LINE__, "No data received from upsc for $ups_name");
return encode_json({ error => "No data from UPS $ups_name" });
}
return JSON->new->pretty->canonical->encode({ $ups_name => $ups_data });
}
# ============================================================================
# UPS — output parser
# ============================================================================
sub _parse_upsc_output {
my ($output) = @_;
my $ups_data = {};
debug(__LINE__, "Parsing upsc output");
eval {
foreach my $line (split /\n/, $output) {
next if $line =~ /^\s*$/;
next if $line =~ /^Init SSL/;
if ($line =~ /^([^:]+):\s*(.*)$/) {
my ($key, $value) = ($1, $2);
$key =~ s/^\s+|\s+$//g;
$value =~ s/^\s+|\s+$//g;
# Coerce numeric values
if ($value =~ /^-?\d+\.?\d*$/) {
$ups_data->{$key} = $value + 0;
} else {
$ups_data->{$key} = $value;
}
}
}
};
if ($@) {
debug(__LINE__, "Error parsing upsc output: $@");
}
debug(__LINE__, "Completed parsing upsc output");
return $ups_data;
}
1;