]> git.proxmox.com Git - pmg-api.git/commitdiff
close #1917: add pmg-system-report command
authorStoiko Ivanov <s.ivanov@proxmox.com>
Mon, 11 Feb 2019 14:43:06 +0000 (15:43 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Tue, 12 Feb 2019 09:27:41 +0000 (10:27 +0100)
pmg-system-report gathers information about a PMG installation, like
pvereport does for PVE.

The name was chosen because pmgreport is already taken (for the daily
reportmails).

The DNS resolution check uses SpamAssassin's internal DnsResolver, since
SpamAssassin has a few pecularities, e.g. only using the first entry in
/etc/resolv.conf - see [0] and Mail::SpamAssassin::DnsResolver and
spam-detection is abysmal if SpamAssassin cannot resolve RBL-entries.
The SpamAssassin initialization is taken from pmg-smtp-filter (except that
local_tests_only is unconditionally disabled (otherwise it would not do DNS
Resolution).

[0] https://wiki.apache.org/spamassassin/DnsBlocklists

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
PMG/Report.pm [new file with mode: 0644]
bin/pmg-system-report [new file with mode: 0755]

diff --git a/PMG/Report.pm b/PMG/Report.pm
new file mode 100644 (file)
index 0000000..aa92366
--- /dev/null
@@ -0,0 +1,134 @@
+package PMG::Report;
+
+use strict;
+use warnings;
+use PVE::Tools;
+use Mail::SpamAssassin::DnsResolver;
+
+$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
+
+my $cmd_timeout = 10; # generous timeout
+
+# NOTE: always add new sections to the report_order array!
+my $report_def = {
+    general => {
+       title => 'general system info',
+       cmds => [
+           'hostname',
+           'pmgversion --verbose',
+           'cat /etc/hosts',
+           'cat /etc/resolv.conf',
+           'top -b -n 1  | head -n 15',
+           'pmgsubscription get',
+           sub { check_dns_resolution() },
+       ],
+    },
+    storage => [
+       'cat /etc/fstab',
+       'findmnt --ascii',
+       'df --human',
+       'lsblk --ascii',
+    ],
+    network => [
+       'ip -details -statistics address',
+       'cat /etc/network/interfaces',
+    ],
+    firewall => [
+       'iptables-save',
+    ],
+    cluster => [
+       'pmgcm status',
+    ],
+    pmg => [
+       'pmgconfig dump',
+       sub { dir2text('/etc/pmg/','(?:domains|mynetworks|tls_policy|transport)' ) },
+       sub { dir2text('/etc/pmg/templates/', '[^.].*' ) },
+       'pmgdb dump',
+       'sa-awl',
+    ],
+};
+
+my @report_order = ('general', 'storage', 'network', 'firewall', 'cluster', 'pmg');
+
+my $report = '';
+
+# output the content of all the files of a directory
+sub dir2text {
+    my ($target_dir, $regexp) = @_;
+
+    PVE::Tools::dir_glob_foreach($target_dir, $regexp, sub {
+       my ($file) = @_;
+       $report .=  "\n# cat $target_dir$file\n";
+       $report .= PVE::Tools::file_get_contents($target_dir.$file)."\n";
+    });
+}
+
+# command -v is the posix equivalent of 'which'
+sub cmd_exists { system("command -v '$_[0]' > /dev/null 2>&1") == 0 }
+
+sub generate {
+
+    my $record_output = sub {
+       $report .= shift . "\n";
+    };
+
+    my $run_cmd_params = {
+       outfunc => $record_output,
+       errfunc => $record_output,
+       timeout => $cmd_timeout,
+       noerr => 1, # avoid checking programs exit code
+    };
+
+    foreach my $section (@report_order) {
+       my $s = $report_def->{$section};
+
+       my $title = "info about $section";
+       my $commands = $s;
+
+       if (ref($s) eq 'HASH') {
+           $commands = $s->{cmds};
+           $title = $s->{title} if defined($s->{title});
+       } elsif (ref($s) ne 'ARRAY') {
+           die "unknown report definition in section '$section'!";
+       }
+
+       $report .= "\n==== $title ====\n";
+       foreach my $command (@$commands) {
+           eval {
+               if (ref $command eq 'CODE') {
+                   PVE::Tools::run_with_timeout($cmd_timeout, $command);
+               } else {
+                   $report .= "\n# $command\n";
+                   PVE::Tools::run_command($command, %$run_cmd_params);
+               }
+           };
+           $report .= "\nERROR: $@\n" if $@;
+       }
+    }
+
+    return $report;
+}
+
+# using SpamAssassin's resolver, since the SA configuration can change which
+# resolver is used and it uses only one resolver.
+sub check_dns_resolution {
+
+    my $sa = Mail::SpamAssassin->new ({
+       debug => 0,
+       local_tests_only => 0,
+       home_dir_for_helpers => '/root',
+       userstate_dir => '/root/.spamassassin',
+       dont_copy_prefs   => 1,
+       stop_at_threshold => 0,
+    });
+    $sa->init();
+
+    my $packet = $sa->{resolver}->send('www.proxmox.com');
+    my $answer = $packet->{answer}->[0];
+    my $answertext = defined($answer) ? $answer->plain() : 'NXDOMAIN';
+
+    $report .= "\n# resolve www.proxmox.com\n";
+    $report .= $answertext . "\n";
+}
+
+1;
diff --git a/bin/pmg-system-report b/bin/pmg-system-report
new file mode 100755 (executable)
index 0000000..5618448
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use PMG::Report;
+
+($> == 0 ) || die "please run as root\n";
+
+print PMG::Report::generate();
+
+__END__
+
+=head1 NAME
+
+pmg-system-report - Proxmox MailGateway system report tool
+
+=head1 SYNOPSIS
+
+pvereport
+
+=head1 DESCRIPTION
+
+Display various information related to a Proxmox MailGateway system