Annotation of trango/Net-Telnet-Trango/scripts/update_trango.pl, Revision 1.29
1.16 mike 1: #!/usr/bin/perl
1.29 ! mike 2: # $RedRiver: update_trango.pl,v 1.28 2007/02/02 22:37:24 andrew Exp $
1.16 mike 3: ########################################################################
1.25 andrew 4: # update_trango.pl *** Updates trango hosts with a new firmware
1.16 mike 5: #
6: # 2005.11.15 #*#*# andrew fresh <andrew@mad-techies.org>
7: ########################################################################
8: use strict;
9: use warnings;
10:
1.23 andrew 11: use YAML qw/ LoadFile /;
1.16 mike 12: use Net::TFTP;
13: use lib '.';
14: use Net::Telnet::Trango;
1.25 andrew 15: use RedRiver::Wireless;
1.16 mike 16:
1.22 andrew 17: my $config_file = shift || 'update_trango.yaml';
1.16 mike 18: my $max_tries = 3;
19:
20: my $l = Mylogger->new( { log_prefix => 'UT' } );
21:
22: $l->sp("Reading config file '$config_file'");
1.22 andrew 23: my $conf = LoadFile($config_file);
1.16 mike 24:
1.27 andrew 25: my $hosts;
26: if (@ARGV) {
27: @{ $hosts } = map { { name => $_, group => 'Trango-Client' } } @ARGV
28: } else {
29: $l->sp("Reading hosts");
30: $hosts = RedRiver::Wireless::Read_Hosts();
31: }
32:
33: #@{ $hosts } = grep { $_->{name} eq '10.100.7.2' } @{ $hosts };
1.22 andrew 34:
1.27 andrew 35: my $global_tries = $max_tries * 2;
36: while ($global_tries > 0) {
37: $global_tries--;
38: my $processed = 0;
1.25 andrew 39:
40:
41: foreach my $host (@{ $hosts }) {
42: next if $host->{group} !~ /^Trango/;
1.27 andrew 43:
44: if (! exists $host->{retry}) {
45: $host->{tries} = 0;
46: $host->{retry} = 1;
47: }
48:
49: if ($host->{tries} >= $max_tries) {
50: $host->{retry} = 0;
51: }
52:
53: if ($host->{retry} <= 0) {
54: next;
55: }
56:
57: $host->{tries}++;
58: $processed++;
59:
1.25 andrew 60: $l->sp("");
1.27 andrew 61: $l->sp("Checking: $host->{name} (try $host->{tries})");
1.22 andrew 62: my $needs_reboot = 0;
1.16 mike 63:
64: ## Connect and login.
65: my $t = new Net::Telnet::Trango (
66: Timeout => 5,
67: Errmode => 'return',
68: ) or die "Couldn't make new connection: $!";
1.25 andrew 69: $l->p("Connecting to $host->{name}");
70: unless ( $t->open($host->{name}) ) {
1.16 mike 71: $l->sp("Error connecting: $!");
72: next;
73: }
74:
1.25 andrew 75: my $password = $host->{Telnet_Password} || $conf->{general}->{password};
76:
1.27 andrew 77: # XXX I am not sure this is the best way to check if we should look for
78: # XXX associated stations.
1.25 andrew 79: if ($host->{group} !~ /Client$/) {
80: $l->p("Logging in");
81: $t->login($password);
82: unless ($t->logged_in) {
83: $l->p('Failed!');
84: $t->close;
85: next;
86: }
87:
88: $l->sp("Getting sudb");
89: my $sudb = $t->sudb_view;
90: if ($sudb) {
1.29 ! mike 91: $t->su_password($password);
1.25 andrew 92: foreach my $su (@{ $sudb }) {
93: $l->p("Getting su info $su->{suid}");
94: my $su_info = $t->su_info( $su->{suid} );
95: if ($su_info->{ip}) {
1.27 andrew 96: if (grep { $_->{name} eq $su_info->{'ip'} } @{ $hosts }) {
97: $l->p("Already have $su_info->{ip}");
98: next;
99: }
1.25 andrew 100: $l->sp("Adding host $su_info->{ip}");
101: my $new_host = {
102: Telnet_Password => $host->{Telnet_Password},
103: group => $host->{group} . '-Client',
104: name => $su_info->{ip},
105: remarks => $su_info->{remarks},
106: };
107: push @{ $hosts }, $new_host;
108: } else {
109: $l->sp("Couldn't get su info for $su->{suid}");
110: if ($su_info->{ERR}) {
111: $l->sp("ERR: $su_info->{ERR}");
112: }
113: }
114: }
115: }
116: }
117:
1.22 andrew 118: foreach my $firmware_type ('Firmware', 'FPGA') {
1.21 mike 119:
1.22 andrew 120: if (! exists $conf->{$firmware_type}) {
1.27 andrew 121: $l->s("No configs for '$firmware_type'");
122: $t->close;
123: next;
124: }
1.22 andrew 125:
126: my $host_type = $t->host_type;
1.23 andrew 127: if ($firmware_type eq 'FPGA') {
1.22 andrew 128: $host_type =~ s/\s.*$//;
129: }
130:
131: if (! exists $conf->{$firmware_type}->{$host_type}) {
1.27 andrew 132: $l->sp("No '$firmware_type' config for type $host_type");
133: $t->close;
1.28 andrew 134: next;
135: }
136:
137: if ($firmware_type eq 'Firmware' &&
138: $t->firmware_version eq
139: $conf->{$firmware_type}->{$host_type}->{ver}
140: ) {
141: $l->sp("Firmware already up to date");
1.27 andrew 142: next;
143: }
1.22 andrew 144:
1.23 andrew 145: if (! $t->logged_in) {
1.22 andrew 146: $l->p("Logging in");
1.25 andrew 147: $t->login($password);
1.23 andrew 148: unless ($t->logged_in) {
149: $l->p('Failed!');
1.25 andrew 150: $t->close;
1.23 andrew 151: next;
152: }
1.22 andrew 153: }
154:
1.27 andrew 155: foreach my $k (keys %{ $conf->{general} }) {
156: $conf->{$firmware_type}->{$host_type}->{$k} ||= $conf->{general}->{$k};
1.22 andrew 157: }
1.27 andrew 158: $conf->{$firmware_type}->{$host_type}->{firmware_type} ||= $firmware_type;
159: $conf->{$firmware_type}->{$host_type}->{type} = $host_type;
1.22 andrew 160:
1.23 andrew 161: $l->sp("$host_type $firmware_type");
1.22 andrew 162: ## Send commands
1.23 andrew 163: my $rc = upload($t, $conf->{$firmware_type}->{$host_type});
1.27 andrew 164: if ($rc) {
1.22 andrew 165: $l->sp("Successfull!");
1.27 andrew 166: $host->{retry}--;
167: $needs_reboot = 1;
1.23 andrew 168: } elsif (defined $rc) {
1.27 andrew 169: $l->sp("Already up to date");
170: $host->{retry}--;
1.22 andrew 171: } else {
1.27 andrew 172: $l->sp("Failed");
173: $t->bye;
174: next;
1.22 andrew 175: }
176:
1.21 mike 177: }
178:
1.22 andrew 179: if ($needs_reboot) {
1.25 andrew 180: $l->sp("Rebooting $host->{name}");
1.17 mike 181: $t->reboot;
182: } else {
1.25 andrew 183: $l->sp("Bye $host->{name}");
1.23 andrew 184: $t->bye();
1.17 mike 185: }
1.16 mike 186: }
187:
1.27 andrew 188: if (! $processed) {
189: $l->sp("");
190: $l->sp("Finished. No more hosts.");
191: last;
192: }
193: }
194:
1.16 mike 195: sub upload
196: {
197: my $t = shift;
1.22 andrew 198: my $conf = shift;
1.16 mike 199:
1.22 andrew 200: my $file = $conf->{firmware_path} . '/' . $conf->{file_name};
201:
202: my $fw_type = $conf->{firmware_type};
1.19 andrew 203:
1.16 mike 204: my $ver = $t->ver;
1.26 andrew 205:
206: if (! (
207: $ver->{$fw_type . ' Version'} &&
208: $ver->{$fw_type . ' Checksum'}
209: )) {
210: $l->sp("Error getting current version numbers");
1.27 andrew 211: return;
1.26 andrew 212: }
1.16 mike 213:
214: if (
1.19 andrew 215: $ver->{$fw_type . ' Version'} eq $conf->{'ver'} &&
216: $ver->{$fw_type . ' Checksum'} eq $conf->{'cksum'}
1.16 mike 217: ) {
1.21 mike 218: return 0;
1.16 mike 219: }
220:
1.27 andrew 221: $l->sp("Updating $fw_type");
1.23 andrew 222: $l->sp("Config information:");
223: $l->sp(" Hardware Type: $conf->{'type'}");
224: $l->sp(" File Name: $conf->{'file_name'}");
225: $l->sp(" File Size: $conf->{'file_size'}");
226: $l->sp(" File Checksum: $conf->{'file_cksum'}");
227: $l->sp(" Conf Version: $conf->{'ver'}");
228: $l->sp(" Cur Version: $ver->{$fw_type . ' Version'}");
229: $l->sp(" Conf Checksum: $conf->{'cksum'}");
230: $l->sp(" Cur Checksum: $ver->{$fw_type . ' Checksum'}");
231:
1.16 mike 232: my $try = 0;
233: while (1) {
234: if ($try >= $max_tries) {
235: $l->sp("Couldn't update in $max_tries tries!");
1.23 andrew 236: return;
1.16 mike 237: }
238: $try++;
239:
240: $l->p("Enabling TFTPd");
1.22 andrew 241: unless ($t->enable_tftpd) {
242: $l->sp("Couldn't enable tftpd");
243: next;
244: }
1.16 mike 245:
1.27 andrew 246: $l->p("Uploading file ($conf->{file_name})");
1.16 mike 247: # use tftp to push the file up
248: my $tftp = Net::TFTP->new($t->Host, Mode => 'octet');
249:
1.21 mike 250: unless ($tftp->put($file, $file)) {
1.22 andrew 251: $l->sp("Error uploading: " . $tftp->error);
1.21 mike 252: next;
253: }
1.16 mike 254:
255: $l->p("Checking upload ($conf->{'file_cksum'})");
256: my $results = $t->tftpd;
257: # check the 'File Length' against ???
1.27 andrew 258: if (! (
259: $results->{'File Checksum'} &&
260: $results->{'File Length'} &&
261: $results->{'File Name'}
262: )) {
263: $l->sp("Unable to get results of upload");
264: next;
265: }
1.16 mike 266: if ( $results->{'File Checksum'} ne $conf->{'file_cksum'}) {
267: $l->sp(
1.27 andrew 268: "File checksum (" . $results->{'File Checksum'} .
269: ") does not match config file (" . $conf->{'file_cksum'} . ")!"
1.16 mike 270: );
271: next;
272: }
273: $l->p("File checksum matches . . . ");
274:
275: if ($results->{'File Length'} !~ /^$conf->{'file_size'} bytes/) {
276: $l->sp(
1.27 andrew 277: "File length (" . $results->{'File Length'} .
278: ") does not match config file (" . $conf->{'file_size'} . " bytes)!"
1.16 mike 279: );
280: next;
281: }
282: $l->p("File length matches . . . ");
283:
1.24 mike 284: if ( uc($results->{'File Name'}) ne uc($file) ) {
1.16 mike 285: $l->sp(
1.27 andrew 286: "File name (" . $results->{'File Name'} .
287: ") does not match config file (" . $file . ")!"
1.16 mike 288: );
289: next;
290: }
1.27 andrew 291: $l->p("File name matches . . . ");
1.16 mike 292:
1.19 andrew 293: my $image_type = 'mainimage';
294: if ($fw_type eq 'FPGA') {
295: $image_type = 'fpgaimage';
296: }
297: $l->p("Updating $image_type (new checksum '$conf->{'cksum'}')");
1.16 mike 298: unless ($results = $t->updateflash(
1.19 andrew 299: args => $image_type . ' ' . $ver->{$fw_type . ' Checksum'} .
1.16 mike 300: ' ' . $conf->{'cksum'},
301: Timeout => 90,
302: ) ) {
303: $l->sp("Couldn't update flash: $!");
304: next;
305: }
306:
307: unless (
308: defined $results->{'Checksum'} &&
309: $results->{'Checksum'} eq $conf->{'cksum'}
310: ) {
1.17 mike 311: $l->sp("Saved checksum " . $results->{'Checksum'} . " does not match config file " . $conf->{'cksum'} . "!");
1.16 mike 312: next;
313: }
1.27 andrew 314:
315: $l->p("$fw_type saved checksum matches . . . ");
1.16 mike 316:
317: return 1;
318: }
319: }
320:
321: package Mylogger;
322:
323: use Fcntl ':flock'; # import LOCK_* constants
324: #use YAML;
325: use constant LOG_PRINT => 128;
326: use constant LOG_SAVE => 64;
327:
328: DESTROY {
329: my $self = shift;
330: if ($self->{'MYLOG'}) {
331: $self->p("Closing log ($self->{'log_path'}/$self->{'log_file'})");
332: close $self->{'MYLOG'};
333: }
334: }
335:
336: sub new {
337: my $package = shift;
338: my $self = shift || {};
339:
340: $self->{'base_path'} ||= '.';
341: $self->{'log_path'} ||= $self->{'base_path'};
342: $self->{'log_prefix'} ||= 'LOG';
343: $self->{'log_file'} ||= GetLogName(
344: $self->{'log_prefix'},
345: $self->{'log_path'}
346: );
347: bless $self, $package;
348: }
349:
350: sub s
351: {
352: my $self = shift;
353: my $m = shift;
354: return $self->mylog($m, LOG_SAVE);
355: }
356:
357: sub p
358: {
359: my $self = shift;
360: my $m = shift;
361: return $self->mylog($m, LOG_PRINT);
362: }
363:
364: sub sp
365: {
366: my $self = shift;
367: my $m = shift;
368: return $self->mylog($m, LOG_SAVE | LOG_PRINT);
369: }
370:
371: sub mylog
372: {
373: my $self = shift;
374:
375: my $thing = shift;
376: chomp $thing;
377:
378: my $which = shift;
379:
380: my $MYLOG;
381: if ($which & LOG_PRINT) {
382: print $thing, "\n";
383: }
384:
385: if ($which & LOG_SAVE) {
386: if ($self->{'MYLOG'}) {
387: $MYLOG = $self->{'MYLOG'};
388: } else {
389: unless ($MYLOG) {
1.27 andrew 390: open ($MYLOG, '>>', $self->{'log_path'} . '/' . $self->{'log_file'})
1.16 mike 391: or die "Couldn't open logfile!\n";
392: my $ofh = select $MYLOG;
393: $|=1;
394: select $ofh;
395: $self->{'MYLOG'} = $MYLOG;
396:
397: $self->p("Opened log ($self->{'log_path'}/$self->{'log_file'})");
398: }
399: }
400: flock($MYLOG, LOCK_EX);
401: print $MYLOG (scalar gmtime), "\t", $thing, "\n"
402: or die "Couldn't print to MYLOG: $!";
403: flock($MYLOG, LOCK_UN);
404: }
405: }
406:
407: sub GetLogName
408: {
409: my $prefix = shift || die "Invalid prefix passed for log";
410:
411: my $logdate = GetLogDate();
412: my $logver = 0;
413: my $logname;
414:
415: do {
416: $logname = $prefix . $logdate . sprintf("%02d", $logver) . '.log';
417: $logver++;
418: } until (not -e $logname);
419:
420: return $logname;
421: }
422:
423: sub GetLogDate
424: {
425: my ($sec,$min,$hour,$mday,$mon,$year,,,) = localtime();
426:
427: $mon++;
428: $year += 1900;
429:
430: if ($min < 10) { $min = "0$min" }
431: if ($sec < 10) { $sec = "0$sec" }
432: if ($hour < 10) { $hour = "0$hour" }
433: if ($mday < 10) { $mday = "0$mday" }
434: if ($mon < 10) { $mon = "0$mon" }
435:
436: my $time = $year . $mon . $mday;
437:
438: return $time;
439: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>