ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/host/ihost-perl/ihost.pl
Revision: 1.26
Committed: Mon Mar 12 23:51:15 2001 UTC (23 years, 8 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.25: +3 -3 lines
Log Message:
Changed the path of the PID file... it didn't work so well when the ihost
directory is on a shared file store :)

File Contents

# Content
1 #!/usr/bin/perl -w
2
3 # -----------------------------------------------------------
4 # Perl i-scream Host.
5 # http://www.i-scream.org.uk
6 #
7 # An all-in-one script to act as an i-scream host on
8 # a typical Unix/Linux box. You may adapt the data-gathering
9 # methods as you see fit.
10 # - pjm2@ukc.ac.uk
11 #
12 # $Author: tdb1 $
13 # $Id: ihost.pl,v 1.25 2001/03/12 23:20:43 tdb1 Exp $
14 #------------------------------------------------------------
15
16 $| = 1;
17
18 use strict;
19 use IO::Socket;
20 use Sys::Hostname;
21
22 use vars qw (
23 $filter_manager_addr
24 $filter_manager_port
25 $seq_no
26 $udp_update_time
27 $tcp_update_time
28 $last_udp_time
29 $last_tcp_time
30 $last_modified
31 $udp_port
32 $tcp_port
33 $filter_addr
34 $file_list
35 $fqdn
36 $pidfile
37 );
38
39 if (@ARGV != 2) {
40 die "Usage: ihost.pl [i-scream filter manager] [TCP port]\n";
41 }
42
43 $filter_manager_addr = $ARGV[0];
44 $filter_manager_port = $ARGV[1];
45
46 $seq_no = 1;
47
48 # write our PID to a file
49 $pidfile = "/var/tmp/ihost.pid";
50 &write_pid();
51
52 &tcp_configure();
53 &send_udp_packet();
54
55 $last_udp_time = time;
56 $last_tcp_time = time;
57 while (1) {
58 my($time) = time;
59 if ($time >= $last_udp_time + $udp_update_time) {
60 &send_udp_packet();
61 $last_udp_time = $time;
62 }
63 if ($time >= $last_tcp_time + $tcp_update_time) {
64 &send_tcp_heartbeat();
65 $last_tcp_time = $time;
66 }
67 my($next_udp) = $udp_update_time - $time + $last_udp_time;
68 my($next_tcp) = $tcp_update_time - $time + $last_tcp_time;
69 my($delay);
70 if ($next_udp < $next_tcp) {
71 $delay = $next_udp
72 }
73 else {
74 $delay = $next_tcp;
75 }
76 `sleep $delay`;
77 }
78
79 # we'll probably never get here...
80 `rm -f $pidfile`;
81 exit(0);
82
83
84 #-----------------------------------------------------------------------
85 # tcp_configure
86 # Establishes a TCP connection to the specified i-scream filter manager.
87 # The host then requests details from the server, such as the intervals
88 # at which to send UDP packets.
89 #-----------------------------------------------------------------------
90 sub tcp_configure() {
91
92 my($sock) = new IO::Socket::INET(
93 PeerAddr => $filter_manager_addr,
94 PeerPort => $filter_manager_port,
95 Proto => 'tcp'
96 ) or die "Cannot connect!";
97 if (!defined $sock) {
98 print "IHOST ERROR: Could not connect to $filter_manager_addr:$filter_manager_port.\n";
99 print "Please check that there is an i-scream server at this address.\n";
100 print "Program ended.\n";
101 exit(1);
102 }
103
104 # Now run through the configuration process...
105 my($response);
106
107 print $sock "STARTCONFIG\n";
108 $response = <$sock>;
109 if (!chop $response eq "OK") {
110 print "The i-scream server rejected the STARTCONFIG command. Terminated.";
111 exit(1);
112 }
113
114 print "Config started okay.\n";
115
116 print $sock "LASTMODIFIED\n";
117 $response = <$sock>;
118 chop $response;
119 $last_modified = $response;
120
121 print "Config last modified: ". (scalar localtime $last_modified/1000) . "\n";
122
123 print $sock "FILELIST\n";
124 $response = <$sock>;
125 chop $response;
126 $file_list = $response;
127
128 print "File list obtained: $file_list\n";
129
130 print $sock "FQDN\n";
131 $response = <$sock>;
132 chop $response;
133 $fqdn = $response;
134
135 print "FQDN returned: $fqdn\n";
136
137 print $sock "UDPUpdateTime\n";
138 $response = <$sock>;
139 chop $response;
140 $udp_update_time = $response;
141
142 print $sock "TCPUpdateTime\n";
143 $response = <$sock>;
144 chop $response;
145 $tcp_update_time = $response;
146
147 print "UDP packet period: $udp_update_time seconds.\nTCP heartbeat period: $tcp_update_time seconds.\n";
148
149 print $sock "ENDCONFIG\n";
150 $response = <$sock>;
151 chomp $response;
152 if (!$response eq "OK") {
153 print "ENDCONFIG command to server failed. Terminated.\n";
154 exit(1);
155 }
156
157 print "Config ended.\n";
158
159 print $sock "FILTER\n";
160 $response = <$sock>;
161 unless (defined($response)) {
162 print "Failed: Could not get a filter address from the filter manager.\n";
163 exit(1);
164 }
165 chop $response;
166 $response =~ /(.*);(.*);(.*)/;
167 ($filter_addr, $udp_port, $tcp_port) = ($1, $2, $3);
168 unless (defined($filter_addr) && defined($udp_port) && defined($tcp_port)) {
169 print "Failed: Filter address response from server did not make sense: $response\n";
170 exit(1);
171 }
172
173 print "Got filter data ($filter_addr, $udp_port, $tcp_port)\n";
174
175 print $sock "END\n";
176 $response = <$sock>;
177 chop $response;
178 if ($response eq "OK") {
179 print "Host successfully configured via TCP.\n"
180 }
181 else {
182 print "The server failed the host configuration on the END command.";
183 exit(1);
184 }
185
186 close($sock);
187
188 print "Configuration finished sucessfully!\n";
189
190 return;
191 }
192
193
194
195
196 #-----------------------------------------------------------------------
197 # send_udp_packet
198 # Sends a UDP packet to an i-scream filter.
199 # The packet contains XML markup describing some of the machine's state.
200 # Receipt of UDP packets is not guaranteed.
201 #-----------------------------------------------------------------------
202 sub send_udp_packet() {
203
204 my(@statgrab) = `./statgrab.pl`;
205 my(%packet);
206 for (my($i) = 0; $i <= $#statgrab; $i++) {
207 $statgrab[$i] =~ /^([^\s]*) (.*)$/;
208 $packet{$1} = $2;
209 }
210
211 my($date) = time;
212
213 my($disk_info) = "<disk>";
214 my($i) = 0;
215 while (defined $packet{"packet.disk.p$i.attributes.mount"}) {
216 $disk_info .= "<p$i";
217 $disk_info .= " name=\"" . $packet{"packet.disk.p$i.attributes.name"} . "\"";
218 $disk_info .= " kbytes=\"" . $packet{"packet.disk.p$i.attributes.kbytes"} . "\"";
219 $disk_info .= " used=\"" . $packet{"packet.disk.p$i.attributes.used"} . "\"";
220 $disk_info .= " avail=\"" . $packet{"packet.disk.p$i.attributes.avail"} . "\"";
221 $disk_info .= " mount=\"" . $packet{"packet.disk.p$i.attributes.mount"} . "\"";
222 $disk_info .= "></p$i>";
223 ++$i;
224 }
225 $disk_info .= "</disk>";
226
227 my($ip) = inet_ntoa(scalar(gethostbyname(hostname())) || 'localhost');
228
229 # Build the XML packet this way, as we can clearly
230 # see the structure and contents... I like this ;-)
231 # [Note that the server rejects UDP packets that are
232 # larger than 8196 bytes]
233 my($xml) = <<EOF;
234
235 <packet seq_no="$seq_no" machine_name="$fqdn" date="$date" type="data" ip="$ip">
236 <load>
237 <load1>$packet{"packet.load.load1"}</load1>
238 <load5>$packet{"packet.load.load5"}</load5>
239 <load15>$packet{"packet.load.load15"}</load15>
240 </load>
241 <os>
242 <name>$packet{"packet.os.name"}</name>
243 <release>$packet{"packet.os.release"}</release>
244 <platform>$packet{"packet.os.platform"}</platform>
245 <sysname>$packet{"packet.os.sysname"}</sysname>
246 <version>$packet{"packet.os.version"}</version>
247 <uptime>$packet{"packet.os.uptime"}</uptime>
248 </os>
249 <users>
250 <count>$packet{"packet.users.count"}</count>
251 <list>$packet{"packet.users.list"}</list>
252 </users>
253 <processes>
254 <total>$packet{"packet.processes.total"}</total>
255 <sleeping>$packet{"packet.processes.sleeping"}</sleeping>
256 <zombie>$packet{"packet.processes.zombie"}</zombie>
257 <stopped>$packet{"packet.processes.stopped"}</stopped>
258 <cpu>$packet{"packet.processes.cpu"}</cpu>
259 </processes>
260 <cpu>
261 <idle>$packet{"packet.cpu.idle"}</idle>
262 <user>$packet{"packet.cpu.user"}</user>
263 <kernel>$packet{"packet.cpu.kernel"}</kernel>
264 <iowait>$packet{"packet.cpu.iowait"}</iowait>
265 <swap>$packet{"packet.cpu.swap"}</swap>
266 </cpu>
267 <memory>
268 <total>$packet{"packet.memory.total"}</total>
269 <free>$packet{"packet.memory.free"}</free>
270 </memory>
271 <swap>
272 <total>$packet{"packet.swap.total"}</total>
273 <free>$packet{"packet.swap.free"}</free>
274 </swap>
275 $disk_info
276 </packet>
277
278 EOF
279
280 # Make the packet smaller by stripping out newlines and leading spaces.
281 $xml =~ s/\n\s*//g;
282
283 my($sock) = new IO::Socket::INET (
284 PeerPort => $udp_port,
285 PeerAddr => $filter_addr,
286 Proto => 'udp'
287 ) or die "Could not send UDP: $!\n";
288
289 print $sock $xml or die "Could not send UDP packet: $!\n";
290 close($sock);
291 $seq_no++;
292 print "-";
293
294 return;
295 }
296
297
298
299
300 #-----------------------------------------------------------------------
301 # send_tcp_heartbeat
302 # Establishes a TCP connection to an i-scream filter.
303 # The heartbeat is used as a guaranteed "I'm alive" delivery mechanism.
304 #-----------------------------------------------------------------------
305 sub send_tcp_heartbeat() {
306
307 my($sock) = new IO::Socket::INET(
308 PeerAddr => $filter_addr,
309 PeerPort => $tcp_port,
310 Proto => 'tcp'
311 ) or return;
312 if (!defined $sock) {
313 print "IHOST WARNING: Failed to deliver a heartbeat to the i-scream filter.\n";
314 return;
315 }
316
317 # Now run through the configuration process.
318 my($response);
319
320 print $sock "HEARTBEAT\n";
321 $response = <$sock>;
322 return if (!defined $response);
323 chop $response;
324 if (!$response eq "OK") {
325 close($sock);
326 print "Server gave wrong response to HEARTBEAT: $response\n";
327 return;
328 }
329
330 print $sock "CONFIG\n";
331 $response = <$sock>;
332 return if (!defined $response);
333 chop $response;
334 if (!$response eq "OK") {
335 close($sock);
336 print "Server gave wrong response to CONFIG: $response\n";
337 return;
338 }
339
340 print $sock "$file_list\n";
341 $response = <$sock>;
342 return if (!defined $response);
343 chop $response;
344 if (!$response eq "OK") {
345 close($sock);
346 print "Server gave wrong response to file list: $response\n";
347 return;
348 }
349
350 print $sock "$last_modified\n";
351 $response = <$sock>;
352 return if (!defined $response);
353 chop $response;
354 if ($response eq "ERROR") {
355 close($sock);
356 &tcp_configure();
357 return;
358 }
359 if (!$response eq "OK") {
360 close($sock);
361 print "Server gave wrong response to HEARTBEAT: $response\n";
362 return;
363 }
364
365 print $sock "ENDHEARTBEAT\n";
366 $response = <$sock>;
367 return if (!defined $response);
368 chop $response;
369 if (!$response eq "OK") {
370 close($sock);
371 print "Server gave wrong response to ENDHEARTBEAT: $response\n";
372 return;
373 }
374
375 close($sock);
376 print "^";
377
378 return;
379 }
380
381 #-----------------------------------------------------------------------
382 # write_pid
383 # Writes the PID (process ID) of this instance to $pidfile.
384 # This is then used by a seperate script to check (and restart) ihost.
385 #-----------------------------------------------------------------------
386 sub write_pid() {
387 open PID, ">$pidfile";
388 print PID $$;
389 close PID;
390
391 return;
392 }