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

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

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