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