]> git.proxmox.com Git - pve-manager.git/blame - bin/pvestatd
fixes for IE9
[pve-manager.git] / bin / pvestatd
CommitLineData
aff192e6
DM
1#!/usr/bin/perl -w
2
3use strict;
4use PVE::SafeSyslog;
5use POSIX ":sys_wait_h";
6use Fcntl ':flock';
7use Getopt::Long;
8use Time::HiRes qw (gettimeofday);
9use PVE::Tools;
10use PVE::ProcFSTools;
11use Filesys::Df;
12use PVE::INotify;
13use PVE::Cluster qw(cfs_read_file);
14use PVE::Storage;
15use PVE::QemuServer;
b3409356 16use PVE::OpenVZ;
aff192e6
DM
17use PVE::RPCEnvironment;
18
19$SIG{'__WARN__'} = sub {
20 my $err = $@;
21 my $t = $_[0];
22 chomp $t;
23 syslog('warning', "WARNING: %s", $t);
24 $@ = $err;
25};
26
27initlog('pvestatd');
28
29$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
30
31die "please run as root\n" if $> != 0;
32
33my $nodename = PVE::INotify::nodename();
34
35my $opt_debug;
36
37if (!GetOptions ('debug' => \$opt_debug)) {
38 die "USAGE: $0 [--debug]\n";
39}
40
41my $opt_pidfile = "/var/run/pvestatd.pid";
42
43sub lockpidfile {
44 my $pidfile = shift;
45 my $lkfn = "$pidfile.lock";
46
47 if (!open (FLCK, ">>$lkfn")) {
48 my $msg = "can't aquire lock on file '$lkfn' - $!";
49 syslog ('err', $msg);
50 die "ERROR: $msg\n";
51 }
52
53 if (!flock (FLCK, LOCK_EX|LOCK_NB)) {
54 close (FLCK);
55 my $msg = "can't aquire lock '$lkfn' - $!";
56 syslog ('err', $msg);
57 die "ERROR: $msg\n";
58 }
59}
60
61sub writepidfile {
62 my $pidfile = shift;
63
64 if (!open (PIDFH, ">$pidfile")) {
65 my $msg = "can't open pid file '$pidfile' - $!";
66 syslog ('err', $msg);
67 die "ERROR: $msg\n";
68 }
69 print PIDFH "$$\n";
70 close (PIDFH);
71}
72
73# try to get the lock
74lockpidfile($opt_pidfile);
75
76# run in background
77my $spid;
78
79my $restart = $ENV{RESTART_PVESTATD};
80
81if (!$opt_debug) {
82 open STDIN, '</dev/null' || die "can't read /dev/null";
83 open STDOUT, '>/dev/null' || die "can't write /dev/null";
84}
85
86if (!$restart && !$opt_debug) {
87 $spid = fork();
88 if (!defined ($spid)) {
89 my $msg = "can't put server into background - fork failed";
90 syslog('err', $msg);
91 die "ERROR: $msg\n";
92 } elsif ($spid) { #parent
93 exit (0);
94 }
95}
96
97writepidfile($opt_pidfile);
98
99open STDERR, '>&STDOUT' || die "can't close STDERR\n";
100
101sub cleanup {
102 unlink "$opt_pidfile.lock";
103 unlink "$opt_pidfile";
104}
105
106$SIG{INT} = $SIG{TERM} = $SIG{QUIT} = sub {
107 syslog('info' , "server closing");
108
109 $SIG{INT} = 'DEFAULT';
110
111 # wait for children
112 1 while (waitpid(-1, POSIX::WNOHANG()) > 0);
113
114 cleanup();
115
116 exit (0);
117};
118
119PVE::INotify::inotify_init();
120
121my $reload_config;
122
123if ($restart) {
124 syslog('info' , "restarting server");
125} else {
126 syslog('info' , "starting server");
127}
128
129$SIG{HUP} = sub {
130 $reload_config = 1;
131};
132
133sub update_node_status {
134
135 my ($avg1, $avg5, $avg15) = PVE::ProcFSTools::read_loadavg();
136
137 my $stat = PVE::ProcFSTools::read_proc_stat();
138
139 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
140
141 my ($uptime) = PVE::ProcFSTools::read_proc_uptime();
142
143 my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
144
145 my $maxcpu = $cpuinfo->{cpus};
146
147 # traffic from/to physical interface cards
148 my $netin = 0;
149 my $netout = 0;
150 foreach my $dev (keys %$netdev) {
151 next if $dev !~ m/^eth\d+$/;
152 $netin += $netdev->{$dev}->{receive};
153 $netout += $netdev->{$dev}->{transmit};
154 }
155
156 my $meminfo = PVE::ProcFSTools::read_meminfo();
157
158 my $dinfo = df('/', 1); # output is bytes
159
160 my $ctime = time();
161
162 # everything not free is considered to be used
163 my $dused = $dinfo->{blocks} - $dinfo->{bfree};
164
165 my $data = "$uptime:$ctime:$avg1:$maxcpu:$stat->{cpu}:$stat->{wait}:" .
166 "$meminfo->{memtotal}:$meminfo->{memused}:" .
167 "$meminfo->{swaptotal}:$meminfo->{swapused}:" .
168 "$dinfo->{blocks}:$dused:$netin:$netout";
169
170 PVE::Cluster::broadcast_rrd("pve2-node/$nodename", $data);
171}
172
173sub update_qemu_status {
174
175 my $ctime = time();
176
177 my $vmstatus = PVE::QemuServer::vmstatus();
178
179 foreach my $vmid (keys %$vmstatus) {
180 my $d = $vmstatus->{$vmid};
181 my $data;
182 if ($d->{pid}) { # running
183 $data = "$d->{uptime}:$d->{name}:$ctime:$d->{cpus}:$d->{cpu}:" .
184 "$d->{maxmem}:$d->{mem}:" .
185 "$d->{maxdisk}:$d->{disk}:" .
186 "$d->{netin}:$d->{netout}:" .
187 "$d->{diskread}:$d->{diskwrite}";
188 } else {
189 $data = "0:$d->{name}:$ctime:$d->{cpus}::" .
190 "$d->{maxmem}::" .
191 "$d->{maxdisk}:$d->{disk}:" .
192 ":::";
193 }
194 PVE::Cluster::broadcast_rrd("pve2-vm/$vmid", $data);
195 }
196}
197
b3409356
DM
198sub update_openvz_status {
199
200 my $ctime = time();
201
202 my $vmstatus = PVE::OpenVZ::vmstatus();
203
204 foreach my $vmid (keys %$vmstatus) {
205 my $d = $vmstatus->{$vmid};
206 my $data;
207 if ($d->{status} eq 'running') { # running
208 $data = "$d->{uptime}:$d->{name}:$ctime:$d->{cpus}:$d->{cpu}:" .
209 "$d->{maxmem}:$d->{mem}:" .
210 "$d->{maxdisk}:$d->{disk}:" .
211 "$d->{netin}:$d->{netout}:" .
212 "$d->{diskread}:$d->{diskwrite}";
213 } else {
214 $data = "0:$d->{name}:$ctime:$d->{cpus}::" .
215 "$d->{maxmem}::" .
216 "$d->{maxdisk}:$d->{disk}:" .
217 ":::";
218 }
219 PVE::Cluster::broadcast_rrd("pve2-vm/$vmid", $data);
220 }
221}
222
aff192e6
DM
223sub update_storage_status {
224
225 my $cfg = cfs_read_file("storage.cfg");
226
227 my $ctime = time();
228
229 my $info = PVE::Storage::storage_info($cfg);
230
231 foreach my $storeid (keys %$info) {
232 my $d = $info->{$storeid};
233 next if !$d->{active};
234
235 # everything not free is considered to be used
236 my $realused = $d->{total} - $d->{avail};
237
238 my $data = "$ctime:$d->{total}:$realused";
239
240 my $key = "pve2-storage/${nodename}/$storeid";
241 PVE::Cluster::broadcast_rrd($key, $data);
242 }
243}
244
245sub update_status {
246
247 # update worker list. This is not really required and
248 # we just call this to make sure that we have a correct
249 # list in case of an unexpected crash.
250 eval {
251 my $tlist = PVE::RPCEnvironment::active_workers();
252 PVE::Cluster::broadcast_tasklist($tlist);
253 };
254 my $err = $@;
255 syslog('err', $err) if $err;
256
257 eval {
258 update_node_status();
259 };
260 $err = $@;
261 syslog('err', "node status update error: $err") if $err;
262
263 eval {
264 update_qemu_status();
265 };
266 $err = $@;
267 syslog('err', "qemu status update error: $err") if $err;
268
b3409356
DM
269 eval {
270 update_openvz_status();
271 };
272 $err = $@;
273 syslog('err', "openvz status update error: $err") if $err;
274
aff192e6
DM
275 eval {
276 update_storage_status();
277 };
278 $err = $@;
279 syslog('err', "storage status update error: $err") if $err;
280}
281
282my $next_update = 0;
283
284# do not update directly after startup, because install scripts
285# have a problem with that
286my $cycle = 0;
287my $updatetime = 10;
288
289my $commandline = [$0, @ARGV];
290
291$0 = "pvestatd";
292
293sub restart_server {
294 my $waittime = shift;
295
296 syslog('info', "server shutdown (restart)");
297
298 $ENV{RESTART_PVESTATD} = 1;
299
300 sleep($waittime) if $waittime; # avoid high server load due to restarts
301
302 exec (@$commandline);
303 exit (-1); # never reached?
304}
305
306for (;;) { # forever
307
308 eval {
309 $next_update = time() + $updatetime;
310
311 if ($cycle) {
312 my ($ccsec, $cusec) = gettimeofday ();
313 eval {
314 $reload_config = 0;
315 syslog('info', "start status update");
316 PVE::Cluster::cfs_update();
317 update_status();
318 };
319 my $err = $@;
320
321 if ($err) {
322 syslog('err', "status update error: $err");
323 }
324
325 my ($ccsec_end, $cusec_end) = gettimeofday ();
326 my $cptime = ($ccsec_end-$ccsec) + ($cusec_end - $cusec)/1000000;
327
328 syslog('info', sprintf("status update finished (%.3f seconds)", $cptime));
329 }
330
331 $cycle++;
332
333 my $mem = PVE::ProcFSTools::read_memory_usage();
334
335 if ($mem->{resident} > (35*1024*1024)) {
336 syslog ('info', "restarting server after $cycle cycles to " .
337 "reduce memory usage (free $mem->{resident} bytes)");
338 restart_server ();
339 }
340
341 my $wcount = 0;
342 while ((time() < $next_update) &&
343 ($wcount < $updatetime) && # protect against time wrap
344 !$reload_config) { $wcount++; sleep (1); };
345 };
346
347 my $err = $@;
348
349 if ($err) {
350 syslog ('err', "ERROR: $err");
351 restart_server(5);
352 exit (0);
353 }
354}
355
356exit (0);
357
358__END__
359
360=head1 NAME
361
362pvestatd - PVE Status Daemon
363
364=head1 SYNOPSIS
365
366pvestatd
367
368=head1 DESCRIPTION
369
370Documentation is available at www.proxmox.com
371
372
373
374
375