]> git.proxmox.com Git - pve-manager.git/blob - PVE/Report.pm
bump version to 8.2.3
[pve-manager.git] / PVE / Report.pm
1 package PVE::Report;
2
3 use strict;
4 use warnings;
5
6 use PVE::Tools;
7
8 # output the content of all the files of a directory
9 my sub dir2text {
10 my ($target_dir, $regexp) = @_;
11
12 print STDERR "dir2text '${target_dir}${regexp}'...";
13 my $text = "# output '${target_dir}${regexp}' file(s)\n";
14 PVE::Tools::dir_glob_foreach($target_dir, $regexp, sub {
15 my ($file) = @_;
16 return if $file eq '.' || $file eq '..';
17 $text .= "\n# cat $target_dir$file\n";
18 $text .= PVE::Tools::file_get_contents($target_dir.$file)."\n";
19 });
20 return $text;
21 }
22
23 # command -v is the posix equivalent of 'which'
24 my sub cmd_exists { system("command -v '$_[0]' > /dev/null 2>&1") == 0 }
25
26 my $init_report_cmds = sub {
27 my $report_def = {
28 general => {
29 title => 'general system info',
30 order => 10,
31 cmds => [
32 'hostname',
33 'date -R',
34 'cat /proc/cmdline',
35 'pveversion --verbose',
36 'cat /etc/hosts',
37 'pvesubscription get',
38 'cat /etc/apt/sources.list',
39 sub { dir2text('/etc/apt/sources.list.d/', '.+\.list') },
40 sub { dir2text('/etc/apt/sources.list.d/', '.+\.sources') },
41 'apt-cache policy | grep -vP "^ +origin "',
42 'apt-mark showhold',
43 'lscpu',
44 'pvesh get /cluster/resources --type node --output-format=yaml',
45 ],
46 },
47 'system-load' => {
48 title => 'overall system load info',
49 order => 20,
50 cmds => [
51 'top -b -c -w512 -n 1 -o TIME | head -n 30',
52 'head /proc/pressure/*',
53 ],
54 },
55 storage => {
56 order => 30,
57 cmds => [
58 'cat /etc/pve/storage.cfg',
59 'pvesm status',
60 'cat /etc/fstab',
61 'findmnt --ascii',
62 'df --human -T',
63 'proxmox-boot-tool status',
64 ],
65 },
66 'virtual guests' => {
67 order => 40,
68 cmds => [
69 'qm list',
70 sub { dir2text('/etc/pve/qemu-server/', '\d+\.conf') },
71 'pct list',
72 sub { dir2text('/etc/pve/lxc/', '\d+\.conf') },
73 ],
74 },
75 network => {
76 order => 45,
77 cmds => [
78 'ip -details -statistics address',
79 'ip -details -4 route show',
80 'ip -details -6 route show',
81 'cat /etc/network/interfaces',
82 sub { dir2text('/etc/network/interfaces.d/', '.*') },
83 sub { dir2text('/etc/pve/sdn/', '.*') },
84 ],
85 },
86 firewall => {
87 order => 50,
88 cmds => [
89 sub { dir2text('/etc/pve/firewall/', '.+\.fw') },
90 'cat /etc/pve/local/host.fw',
91 'iptables-save -c | column -t -l4 -o" "',
92 ],
93 },
94 cluster => {
95 order => 60,
96 cmds => [
97 'pvecm nodes',
98 'pvecm status',
99 'cat /etc/pve/corosync.conf 2>/dev/null',
100 'ha-manager status',
101 'cat /etc/pve/datacenter.cfg',
102 ],
103 },
104 jobs => {
105 order => 65,
106 cmds => [
107 'cat /etc/pve/jobs.cfg',
108 ],
109 },
110 hardware => {
111 order => 70,
112 cmds => [
113 'dmidecode -t bios',
114 'lspci -nnk',
115 ],
116 },
117 'block devices' => {
118 order => 80,
119 cmds => [
120 'lsblk --ascii -M -o +HOTPLUG,ROTA,PHY-SEC,FSTYPE,MODEL,TRAN',
121 'ls -l /dev/disk/by-*/',
122 'iscsiadm -m node',
123 'iscsiadm -m session',
124 ],
125 },
126 volumes => {
127 order => 90,
128 cmds => [
129 'pvs',
130 'lvs',
131 'vgs',
132 ],
133 },
134 };
135
136 if (cmd_exists('zfs')) {
137 push @{$report_def->{volumes}->{cmds}},
138 'zpool status',
139 'zpool list -v',
140 'zfs list',
141 'arcstat',
142 ;
143 }
144
145 if (-e '/etc/ceph/ceph.conf') {
146 push @{$report_def->{volumes}->{cmds}},
147 'pveceph status',
148 'ceph osd status',
149 'ceph df',
150 'ceph osd df tree',
151 'ceph device ls',
152 'cat /etc/ceph/ceph.conf',
153 'ceph config dump',
154 'pveceph pool ls',
155 'ceph versions',
156 'ceph health detail',
157 ;
158 }
159
160 if (cmd_exists('multipath')) {
161 push @{$report_def->{disks}->{cmds}},
162 'cat /etc/multipath.conf',
163 'cat /etc/multipath/wwids',
164 'multipath -ll',
165 ;
166 }
167
168 return $report_def;
169 };
170
171 sub generate {
172 my $def = $init_report_cmds->();
173
174 my $report = '';
175 my $record_output = sub {
176 $report .= shift . "\n";
177 };
178
179 local $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
180 my $cmd_timeout = 10; # generous timeout
181
182 my $run_cmd_params = {
183 outfunc => $record_output,
184 errfunc => $record_output,
185 timeout => $cmd_timeout,
186 noerr => 1, # avoid checking programs exit code
187 };
188
189 my $sorter = sub { ($def->{$_[0]}->{order} // 1<<30) <=> ($def->{$_[1]}->{order} // 1<<30) };
190
191 for my $section ( sort { $sorter->($a, $b) } keys %$def) {
192 my $s = $def->{$section};
193 my $title = $s->{title} // "info about $section";
194
195 $report .= "\n==== $title ====\n";
196 for my $command (@{$s->{cmds}}) {
197 eval {
198 if (ref $command eq 'CODE') {
199 $report .= PVE::Tools::run_with_timeout($cmd_timeout, $command);
200 } else {
201 print STDERR "Process ".$command."...";
202 $report .= "\n# $command\n";
203 PVE::Tools::run_command($command, %$run_cmd_params);
204 }
205 print STDERR "OK";
206 };
207 print STDERR "\n";
208 $report .= "\nERROR: $@\n" if $@;
209 }
210 }
211
212 return $report;
213 }
214
215 1;