[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.33

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>