[BACK]Return to update_trango.pl CVS log [TXT][DIR] Up to [local] / trango / Net-Telnet-Trango / scripts

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>