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.17
Committed: Tue Feb 27 19:14:26 2001 UTC (23 years, 9 months ago) by pjm2
Content type: text/plain
Branch: MAIN
Changes since 1.16: +10 -2 lines
Log Message:
Updated to comply with the new FilterManger configuration protocol.
Namely, the ihost now also sends "FQDN" to the server to request its fully
qualified domain name.  This simplifies the task of writing hosts as it no
longer means that the host has to work out its own machine name (which is
sometimes a non-trivial task on certain platforms)

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