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

1.16      mike        1: #!/usr/bin/perl
1.34    ! andrew      2: # $RedRiver: update_trango.pl,v 1.33 2007/02/07 22:07:35 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.34    ! andrew    167:                 $l->sp("Failed! - Bye $host->{name}");
        !           168:                 $l->e("Error updating $firmware_type on $host->{name}" .
        !           169:                     "(try $host->{tries})");
1.31      andrew    170:                 $t->bye;
1.34    ! andrew    171:                 # don't try any other firmware, don't want to reboot
        !           172:                 last;
1.31      andrew    173:             }
1.22      andrew    174:
1.31      andrew    175:         }
1.22      andrew    176:
1.31      andrew    177:         if ($needs_reboot) {
                    178:             $l->sp("Rebooting $host->{name}");
                    179:             $t->reboot;
1.33      andrew    180:         }
                    181:         else {
1.31      andrew    182:             $l->sp("Bye $host->{name}");
                    183:             $t->bye();
                    184:         }
1.22      andrew    185:     }
                    186:
1.33      andrew    187:     if ( !$processed ) {
1.31      andrew    188:         $l->sp("");
                    189:         $l->sp("Finished.  No more hosts.");
                    190:         last;
1.22      andrew    191:     }
1.27      andrew    192: }
                    193:
1.33      andrew    194: sub upload {
1.31      andrew    195:     my $t    = shift;
                    196:     my $conf = shift;
1.16      mike      197:
1.31      andrew    198:     my $file = $conf->{firmware_path} . '/' . $conf->{file_name};
1.22      andrew    199:
1.31      andrew    200:     my $fw_type = $conf->{firmware_type};
1.19      andrew    201:
1.31      andrew    202:     my $ver = $t->ver;
1.26      andrew    203:
1.33      andrew    204:     if (
                    205:         !(
                    206:             $ver->{ $fw_type . ' Version' } && $ver->{ $fw_type . ' Checksum' }
                    207:         )
                    208:       )
                    209:     {
1.31      andrew    210:         $l->sp("Error getting current version numbers");
                    211:         return;
1.16      mike      212:     }
                    213:
1.33      andrew    214:     if (   $ver->{ $fw_type . ' Version' } eq $conf->{'ver'}
                    215:         && $ver->{ $fw_type . ' Checksum' } eq $conf->{'cksum'} )
                    216:     {
1.31      andrew    217:         return 0;
1.22      andrew    218:     }
1.16      mike      219:
1.31      andrew    220:     $l->sp("Updating $fw_type");
                    221:     $l->sp("Config information:");
                    222:     $l->sp("  Hardware Type: $conf->{'type'}");
                    223:     $l->sp("  File Name:     $conf->{'file_name'}");
                    224:     $l->sp("  File Size:     $conf->{'file_size'}");
                    225:     $l->sp("  File Checksum: $conf->{'file_cksum'}");
                    226:     $l->sp("  Conf Version:  $conf->{'ver'}");
                    227:     $l->sp("  Cur  Version:  $ver->{$fw_type . ' Version'}");
                    228:     $l->sp("  Conf Checksum: $conf->{'cksum'}");
                    229:     $l->sp("  Cur  Checksum: $ver->{$fw_type . ' Checksum'}");
                    230:
                    231:     my $try = 0;
                    232:     while (1) {
1.33      andrew    233:         if ( $try >= $max_tries ) {
1.31      andrew    234:             $l->sp("Couldn't update in $max_tries tries!");
                    235:             return;
                    236:         }
                    237:         $try++;
                    238:
                    239:         $l->p("Enabling TFTPd");
1.33      andrew    240:         unless ( $t->enable_tftpd ) {
1.31      andrew    241:             $l->sp("Couldn't enable tftpd");
                    242:             next;
                    243:         }
                    244:
                    245:         $l->p("Uploading file ($conf->{file_name})");
1.33      andrew    246:
1.31      andrew    247:         # use tftp to push the file up
1.33      andrew    248:         my $tftp = Net::TFTP->new( $t->Host, Mode => 'octet' );
1.31      andrew    249:
1.33      andrew    250:         unless ( $tftp->put( $file, $file ) ) {
                    251:             $l->sp( "Error uploading: " . $tftp->error );
1.31      andrew    252:             next;
                    253:         }
                    254:
                    255:         $l->p("Checking upload ($conf->{'file_cksum'})");
                    256:         my $results = $t->tftpd;
1.33      andrew    257:
1.31      andrew    258:         # check the 'File Length' against ???
1.33      andrew    259:         if (
                    260:             !(
                    261:                    $results->{'File Checksum'}
                    262:                 && $results->{'File Length'}
                    263:                 && $results->{'File Name'}
                    264:             )
                    265:           )
                    266:         {
1.31      andrew    267:             $l->sp("Unable to get results of upload");
                    268:             next;
                    269:         }
1.33      andrew    270:         if ( $results->{'File Checksum'} ne $conf->{'file_cksum'} ) {
                    271:             $l->sp( "File checksum ("
                    272:                   . $results->{'File Checksum'}
                    273:                   . ") does not match config file ("
                    274:                   . $conf->{'file_cksum'}
                    275:                   . ")!" );
1.31      andrew    276:             next;
1.33      andrew    277:         }
1.31      andrew    278:         $l->p("File checksum matches . . . ");
                    279:
1.33      andrew    280:         if ( $results->{'File Length'} !~ /^$conf->{'file_size'} bytes/ ) {
                    281:             $l->sp( "File length ("
                    282:                   . $results->{'File Length'}
                    283:                   . ") does not match config file ("
                    284:                   . $conf->{'file_size'}
                    285:                   . " bytes)!" );
1.31      andrew    286:             next;
                    287:         }
                    288:         $l->p("File length matches . . . ");
                    289:
1.33      andrew    290:         if ( uc( $results->{'File Name'} ) ne uc($file) ) {
                    291:             $l->sp( "File name ("
                    292:                   . $results->{'File Name'}
                    293:                   . ") does not match config file ("
                    294:                   . $file
                    295:                   . ")!" );
1.31      andrew    296:             next;
                    297:         }
                    298:         $l->p("File name matches . . . ");
1.16      mike      299:
1.31      andrew    300:         my $image_type = 'mainimage';
1.33      andrew    301:         if ( $fw_type eq 'FPGA' ) {
1.31      andrew    302:             $image_type = 'fpgaimage';
                    303:         }
                    304:         $l->p("Updating $image_type (new checksum '$conf->{'cksum'}')");
1.33      andrew    305:         unless (
                    306:             $results = $t->updateflash(
                    307:                 args => $image_type . ' '
                    308:                   . $ver->{ $fw_type . ' Checksum' } . ' '
                    309:                   . $conf->{'cksum'},
1.31      andrew    310:                 Timeout => 90,
1.33      andrew    311:             )
                    312:           )
                    313:         {
1.31      andrew    314:             $l->sp("Couldn't update flash: $!");
                    315:             next;
                    316:         }
1.16      mike      317:
1.33      andrew    318:         unless ( defined $results->{'Checksum'}
                    319:             && $results->{'Checksum'} eq $conf->{'cksum'} )
                    320:         {
                    321:             $l->sp( "Saved checksum "
                    322:                   . $results->{'Checksum'}
                    323:                   . " does not match config file "
                    324:                   . $conf->{'cksum'}
                    325:                   . "!" );
1.31      andrew    326:             next;
                    327:         }
1.16      mike      328:
1.31      andrew    329:         $l->p("$fw_type saved checksum matches . . . ");
1.16      mike      330:
1.31      andrew    331:         return 1;
1.16      mike      332:     }
1.30      andrew    333: }
                    334:
1.33      andrew    335: sub parse_hosts {
1.30      andrew    336:     my $src = shift;
                    337:
                    338:     my @hosts;
1.33      andrew    339:     foreach my $h ( @{$src} ) {
                    340:         if ( $h->{name} =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})-(\d{1,3})/ )
                    341:         {
                    342:             for ( $2 .. $3 ) {
1.30      andrew    343:                 my %cur_host;
1.33      andrew    344:                 foreach my $k ( keys %{$h} ) {
1.30      andrew    345:                     $cur_host{$k} = $h->{$k};
                    346:                 }
                    347:                 $cur_host{name} = $1 . $_;
1.33      andrew    348:                 if ( !grep { $cur_host{name} eq $h->{name} } @hosts ) {
1.30      andrew    349:                     push @hosts, \%cur_host;
                    350:                 }
                    351:             }
1.33      andrew    352:         }
                    353:         else {
1.30      andrew    354:             push @hosts, $h;
                    355:         }
                    356:     }
                    357:
                    358:     return \@hosts;
1.16      mike      359: }
                    360:
                    361: package Mylogger;
                    362:
1.33      andrew    363: use Fcntl ':flock';    # import LOCK_* constants
                    364:
1.16      mike      365: #use YAML;
                    366: use constant LOG_PRINT => 128;
1.33      andrew    367: use constant LOG_SAVE  => 64;
1.34    ! andrew    368: use constant LOG_ERR   => 1;
1.16      mike      369:
                    370: DESTROY {
1.31      andrew    371:     my $self = shift;
1.33      andrew    372:     if ( $self->{'MYLOG'} ) {
1.31      andrew    373:         $self->p("Closing log ($self->{'log_path'}/$self->{'log_file'})");
                    374:         close $self->{'MYLOG'};
                    375:     }
1.16      mike      376: }
                    377:
                    378: sub new {
1.31      andrew    379:     my $package = shift;
                    380:     my $self = shift || {};
1.16      mike      381:
1.31      andrew    382:     $self->{'base_path'}  ||= '.';
                    383:     $self->{'log_path'}   ||= $self->{'base_path'};
                    384:     $self->{'log_prefix'} ||= 'LOG';
1.33      andrew    385:     $self->{'log_file'} ||=
                    386:       GetLogName( $self->{'log_prefix'}, $self->{'log_path'} );
1.31      andrew    387:     bless $self, $package;
1.16      mike      388: }
                    389:
1.33      andrew    390: sub s {
1.31      andrew    391:     my $self = shift;
1.33      andrew    392:     my $m    = shift;
                    393:     return $self->mylog( $m, LOG_SAVE );
1.16      mike      394: }
                    395:
1.33      andrew    396: sub p {
1.31      andrew    397:     my $self = shift;
1.33      andrew    398:     my $m    = shift;
                    399:     return $self->mylog( $m, LOG_PRINT );
1.16      mike      400: }
                    401:
1.33      andrew    402: sub sp {
1.31      andrew    403:     my $self = shift;
1.33      andrew    404:     my $m    = shift;
                    405:     return $self->mylog( $m, LOG_SAVE | LOG_PRINT );
1.16      mike      406: }
                    407:
1.34    ! andrew    408: sub e {
        !           409:     my $self = shift;
        !           410:     my $m    = shift;
        !           411:     return $self->mylog( $m, LOG_ERR );
        !           412: }
        !           413:
1.33      andrew    414: sub mylog {
1.31      andrew    415:     my $self = shift;
1.16      mike      416:
1.31      andrew    417:     my $thing = shift;
                    418:     chomp $thing;
1.16      mike      419:
1.31      andrew    420:     my $which = shift;
1.16      mike      421:
1.31      andrew    422:     my $MYLOG;
1.33      andrew    423:     if ( $which & LOG_PRINT ) {
1.31      andrew    424:         print $thing, "\n";
                    425:     }
1.16      mike      426:
1.33      andrew    427:     if ( $which & LOG_SAVE ) {
                    428:         if ( $self->{'MYLOG'} ) {
1.31      andrew    429:             $MYLOG = $self->{'MYLOG'};
1.33      andrew    430:         }
                    431:         else {
1.31      andrew    432:             unless ($MYLOG) {
1.33      andrew    433:                 open( $MYLOG, '>>',
                    434:                     $self->{'log_path'} . '/' . $self->{'log_file'} )
                    435:                   or die "Couldn't open logfile!\n";
1.31      andrew    436:                 my $ofh = select $MYLOG;
1.33      andrew    437:                 $| = 1;
1.31      andrew    438:                 select $ofh;
                    439:                 $self->{'MYLOG'} = $MYLOG;
1.16      mike      440:
1.33      andrew    441:                 $self->p(
                    442:                     "Opened log ($self->{'log_path'}/$self->{'log_file'})");
1.31      andrew    443:             }
                    444:         }
1.33      andrew    445:         flock( $MYLOG, LOCK_EX );
                    446:         print $MYLOG ( scalar gmtime ), "\t", $thing, "\n"
                    447:           or die "Couldn't print to MYLOG: $!";
                    448:         flock( $MYLOG, LOCK_UN );
1.34    ! andrew    449:     }
        !           450:
        !           451:     if ( $which & LOG_ERR ) {
        !           452:         # XXX Could tie in here to handle some sort of notifications.
        !           453:         print STDERR $thing, "\n";
1.16      mike      454:     }
                    455: }
                    456:
1.33      andrew    457: sub GetLogName {
                    458:     my $prefix = shift || die "Invalid prefix passed for log";
1.16      mike      459:
1.31      andrew    460:     my $logdate = GetLogDate();
                    461:     my $logver  = 0;
                    462:     my $logname;
                    463:
                    464:     do {
1.33      andrew    465:         $logname = $prefix . $logdate . sprintf( "%02d", $logver ) . '.log';
1.31      andrew    466:         $logver++;
1.33      andrew    467:     } until ( not -e $logname );
1.16      mike      468:
1.31      andrew    469:     return $logname;
1.16      mike      470: }
                    471:
1.33      andrew    472: sub GetLogDate {
                    473:     my ( $sec, $min, $hour, $mday, $mon, $year,,, ) = localtime();
1.16      mike      474:
1.31      andrew    475:     $mon++;
                    476:     $year += 1900;
1.16      mike      477:
1.33      andrew    478:     if ( $min  < 10 ) { $min  = "0$min"  }
                    479:     if ( $sec  < 10 ) { $sec  = "0$sec"  }
                    480:     if ( $hour < 10 ) { $hour = "0$hour" }
                    481:     if ( $mday < 10 ) { $mday = "0$mday" }
                    482:     if ( $mon  < 10 ) { $mon  = "0$mon"  }
1.16      mike      483:
1.31      andrew    484:     my $time = $year . $mon . $mday;
1.16      mike      485:
1.31      andrew    486:     return $time;
1.16      mike      487: }

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