#!/usr/bin/perl -I/opt/SUNWstade/lib
use strict;

use Getopt::Std;
use System;
use Net::Telnet;
use MIME::Base64;
use Process;

System->set_home("/opt/SUNWstade");
use vars qw(%opts $DIR1 $DIR $SPDIR $DSPDIR $T3DIR $SW $SWDIR $VEDIR $STDIR $PPDIR $SEDIR $debug_out $SECFG $T3PWD $DEBUGF $TAR $LOG);

sub usage {
  print <<EOF;
Usage: se_extract -r -t <array_password> -d [1|2] -s [status] -p [print] -b [background]
     -d : debug level
     -t : array password, all the same
     -s : status of extract run
     -p : print extract log
     -x : return the tar file immediately to stdout with http header.
     -r : run
     -b : background
EOF
}
use vars qw ($DEBUG);
System->set_rasport(7654);

if (!getopts("xbrspPbd:ht:", \%opts) || $opts{h}) {
    usage();
    exit(1);
}
my $ID      = "Extract";
my $done;

if ($opts{s}) {
   my $st = Process->status($opts{h}, $ID);
   print "$st \n";
   exit;
}

if ($opts{r}) {
  my $st = Process->status($opts{h}, $ID);
  if ($st =~ /Running/) {
     print "Solution Extract already running!\n";
     exit(1);
  }
  my $opt = "-r" if ($opts{r}) ;
  $opt    = " -t $opts{t}" if ($opts{t});
  $opt   .= " -d $opts{d}" if ($opts{d});
  Process->run($opts{h}, "sysbin/se_extract $opt", \ &run, !$opts{b}, 60*60, \&printnew);
  $done++;
}

if ($opts{p} || $opts{P}) {
    if (open(O, System->get_home() . "/DATA/Download/Solution/Extract_log.txt")) {
      my @L = <O>; close(O);
      print join("", @L);
    } else {
      print "Error opening extract_log: $!\n";
    }
    $done++;
}

if ($opts{x}) {
  &print_tar();
  $done++;
}
if (!$done) {
   print "\nNo option selected!\n\n";
   usage();
   exit();
}





sub print_tar {
   if (!open(O, $TAR) ) {
       print "ERROR: Cannot open $TAR: $!\n";
       return;
   }
   my $size = (stat($TAR))[7];

   my $l;
   while (read(O, $l, 1000)) {
       print $l;
   }
   close(O);
}



sub run {

  Process->start($ID);
  my($renv, $devs, $hosts, $notifs) = PDM::ConfigFile->read();
  my $se = $renv->{solution_model} . "." . System->hostid();

  my $today = Util->get_today();
  $today =~ s/ /_/g;
  $today =~ s/\://g;
  
  $SW     = "/opt/SUNWstade";
  my $DIR0= "$SW/DATA/Download";
  $DIR1   = "$SW/DATA/Download/Solution";
  $DIR    = "$SW/DATA/Download/Solution/$se";
  my $array_p = System->getPassword("array");

  if ($opts{t}) {
     $T3PWD = $opts{t};
  } elsif ($array_p) {
     $T3PWD = $array_p;
  } else {
     $T3PWD = "sun1";
  }
  $SECFG  = "/opt/SUNWsecfg/bin";
  $DEBUG  = $opts{d};
  
  $SPDIR  = "$DIR/Sp";
  $T3DIR  = "$DIR/Arrays";
  $DSPDIR = "$DIR/DSP";
  $SWDIR  = "$DIR/Switches";
  $VEDIR  = "$DIR/Ves";
  $STDIR  = "$DIR/Storade";
  $SEDIR  = "$DIR/Rack";
  $PPDIR  = "$DIR/PatchPro";
  $DEBUGF = "$DIR1/$se/extract_log.txt";
  $TAR    = "$DIR1/extract_${se}_$today.tar";
  $LOG    = "$DIR1/log_${se}_$today.txt";
  
  mkdir  $DIR0,  0777;
  mkdir  $DIR1,  0777;
  mkdir  $DIR,   0777;
  mkdir  $STDIR, 0777;
  mkdir  $T3DIR, 0777;
  mkdir  $SWDIR, 0777;
  mkdir  $VEDIR, 0777;
  mkdir  $SPDIR, 0777;
  mkdir  $SEDIR, 0777;
  mkdir  $PPDIR, 0777;

  unlink $LOG;
  
  $ENV{PATH} .= $ENV{PATH} . "/bin:/usr/bin:$SW/bin";
  
  &indy();
  &dsp($devs);
  &patchpro();
  &storade($renv);
  &sp();
  &switches($devs);
  &t3s($devs);
  &ves($devs);
  
  chdir($DIR1); 
  
  debug("\n-> TAR..");
  system2("tar cf $TAR $se");
  
  if (-f $DEBUGF) {
    system("cp $DEBUGF $LOG");
  }

  unlink "$DIR1/Extract.tar";
  unlink "$DIR1/Extract_log.txt";
  system("ln -s $TAR   $DIR1/Extract.tar");
  system("ln -s $LOG   $DIR1/Extract_log.txt");
  
  &clean("extract_", 5);
  &clean("log_", 5);

  my $report;
  $report->{debug}  = $DEBUG;
  $report->{error_cnt}  = 0;
  $report->{data}   = {trace => $DEBUG, report => $debug_out };
  $report->{display_method} = "Service::Extract::report";
  $report->{date}   = Util->get_today();

  Process->write($report, $ID);
  sleep(2);
  Process->done($ID);

}

sub clean {
  my($pat, $max) = @_;

  opendir(O, $DIR1);
  my @D = readdir(O); closedir(O);
  my $cnt;
  foreach my $d (@D) {
    next if ($d !~ /^$pat/);
    $cnt++;
  }
  
  if ($cnt > $max) {
    foreach my $d (sort @D) {
      next if ($d !~ /^$pat/);
      last if ($cnt-- < $max);
      unlink "$DIR1/$d";
    }
  }
}


######################
# DSP 

sub dsp {
  my($F, $devs) = @_;
  my $out;
  foreach my $dev (@$devs) {
     next if (index("dsp", $dev->{type}) < 0);

     my $F = "$DSPDIR/$dev->{name}";
     mkdir  $F, 0777;
     &debug("  -> $dev->{type} $dev->{name}..");

     my $t= Net::Telnet->new(
	Timeout => 90,
        errmode => "return",
 	Prompt => '/([#?] $|\033\[\dD )/',
         );

     return "Cannot telnet to $dev->{name}" if (!$t);

     if (!defined($t->open($dev->{ipno} ))) {
        return "Cannot telnet:open $dev->{name}/$dev->{ipno}";
     }
    $t->max_buffer_length(500000);

    $t->login('root',$T3PWD);

    if ($t->errmsg()) {
       return $t->errmsg();
    }
    $out .= &command($F, $t, "config");
    $out .= &command($F, $t, "no page-mode");
    $out .= &command($F, $t, "show support");
    $out .= &command($F, $t, "exit");
    $out .= &command($F, $t, "exit");
  }
}


######################
# INDY

sub indy {

  my ($i, @switches, @ves);
  &debug("\n-> MODULE: Indy ..");

  system2("cp /etc/hosts      $SEDIR/etc_hosts");
  system2("cp /etc/motd       $SEDIR/etc_motd");
  system2("cp /etc/release    $SEDIR/etc_release");

  if (-x "$SECFG/getcabinet") {
    system2("$SECFG/getcabinet > $SEDIR/getcabinet 2>&1");
    my $ss = `$SECFG/listavailable -s`;
    chop($ss);
    foreach $i (split(/\s+/, $ss)) {
       system2("$SECFG/showswitch -s $i > $SEDIR/showswitch_$i 2>&1");
    }
    $ss = `$SECFG/listavailable -v`;
    chop($ss);
    my $all;
    foreach $i (split(/\s+/, $ss)) {
       my $mn =  substr($i,0,2) ;
       if (index(",$all,", ",$mn,") < 0 ) {
         system2("$SECFG/showvemap -n $mn -l > $SEDIR/showvemap_$i 2>&1");
         $all .= "$mn,";
       }
    }
    system2("cp /export/README.txt      $SEDIR/export_readme.txt");
    system2("tail -1000 /var/adm/log/SEcfglog > $SEDIR/SE_cfg_log 2>&1");
    opendir(O, "/opt/SUNWsecfg/etc");
    my @d = readdir(O); closedir(O);
    my $out;
    foreach my $f (@d) {
       next if ($f !~ /\.cfg/);
       $out .= "\n====================\n| $f\n=====================\n";
       open(O, "/opt/SUNWsecfg/etc/$f");
       my @l = <O>; close(O);
       $out .= join("", @l);
    }
    open(O, ">$SEDIR/etc_configs");
    print O $out;
    close(O);
  }
}

sub patchpro {
  my ($i);
  &debug("\n-> MODULE: PatchPro..");

  if (-f "/var/log/patchpro.log") {
     system2("cp /var/log/patchpro.log             $PPDIR/patchpro.log");
  }
  if (-f "/etc/opt/SUNWppro/etc/patchpro.conf") {
     system2("cp /etc/opt/SUNWppro/etc/patchpro.conf   $PPDIR/patchpro.conf");
  }
}

sub system2 {
  my($com) = @_;
  my $com0 = $com;
  my $ix = index($com, "> ");
  if ($ix > 0) {
     $com0 = substr($com,0,$ix);
  }
  &debug2("    -> $com0 ..");
  system($com);
}
  
sub storade {
  my($renv) = @_;
  my $hn = $renv->{hostname};
  &debug("\n-> MODULE: Storade ..");
  system2("cp $SW/DATA/rasagent.conf       $STDIR/rasagent.conf");
  system2("cp $SW/DATA/Events.log          $STDIR/Events.log");
  system2("pkginfo -l SUNWstads >          $STDIR/pkginfo_SUNWstade 2>&1");
  if (-x "/usr/bin/showrev") {
    system2("/usr/bin/showrev -p|grep SUNWstade >     $STDIR/showrev_SUNWstade 2>&1");
  }
  system2("$SW/bin/ras_admin site_info >   $STDIR/ras_admin_site_info");
  system2("$SW/bin/ras_admin topo -t MERGE-MASTER > $STDIR/ras_admin_topo_MASTER");
  system2("$SW/bin/ras_admin topo -t $hn   > $STDIR/ras_admin_topo_$hn");
  system2("$SW/bin/ras_admin device_list > $STDIR/ras_admin_device_list");
  system2("$SW/bin/ras_admin email_list >  $STDIR/ras_admin_email_list");
  system2("$SW/bin/ras_admin provider_list > $STDIR/ras_admin_provider_list");
  open(O, ">$STDIR/MODEL_$renv->{solution_model}"); close(O);

  chdir $SW;
  system2("cp -r /var/opt/SUNWstade/DATA/OLD_REPORTS $STDIR");
  
}

sub switches {
  my($devs) = @_; 
  my $PORT = "-port 5003";
  &debug("\n-> MODULE: Switch ..");
  foreach my $dev (@$devs) {
     next if ($dev->{type} !~ /^switch/);
     &debug("  -> $dev->{name} ..");
     my $F = "$SWDIR/$dev->{name}";
     mkdir  $F, 0777;
     my $out ;
     my $sanbox = $dev->{type} =~ /switch2/ ? "sanbox2" : "sanbox";
     if (!Util->ping($dev->{ipno})){
        &debug("ERROR: CANNOT PING $dev->{name}/$dev->{ipno}\n");
     } else {
       $out .= &run1($F, "$sanbox version $PORT $dev->{ipno} 2>&1");
       $out .= &run1($F, "$sanbox chassis_id $PORT $dev->{ipno}");
       $out .= &run1($F, "$sanbox chassis_status $PORT $dev->{ipno}");
       $out .= &run1($F, "$sanbox links $PORT $dev->{ipno}");
       $out .= &run1($F, "$sanbox port_counts $PORT $dev->{ipno} all");
       $out .= &run1($F, "$sanbox port_status $PORT $dev->{ipno} all");
       $out .= &run1($F, "$sanbox port_state $PORT $dev->{ipno} all");
       $out .= &run1($F, "$sanbox chassis_counters $PORT $dev->{ipno} all");
       $out .= &run1($F, "$sanbox get_zone $PORT $dev->{ipno} hd all");
       $out .= &run1($F, "$sanbox get_zone $PORT $dev->{ipno} sl all");
       $out .= &run1($F, "$sanbox nameserver $PORT $dev->{ipno}");
     }
  }
  
}


sub sp {

  &debug("\n-> MODULE: SP ");
  system2("cp /etc/services $SPDIR/service");
  system2("cp /etc/inetd.conf $SPDIR/inetd.conf");
  system2("ps -ef > $SPDIR/ps_ef");
  system2("df -k > $SPDIR/df_k");
  
  chdir "/var/adm";
  system2("/usr/bin/tar cf /tmp/sa_messages.tar messages*");
  system2("/usr/bin/compress /tmp/sa_messages.tar");
  system2("/bin/cp /tmp/sa_messages.tar.Z $SPDIR/var_adm_logfiles.tar.Z");
  system2("/bin/rm /tmp/sa_messages.*");

  chdir "/var/tmp";
  system2("/usr/bin/tar cf /tmp/se_messages.tar *");
  system2("/usr/bin/compress /tmp/se_messages.tar");
  system2("/bin/cp /tmp/se_messages.tar.Z $SPDIR/var_tmp_logfiles.tar.Z");
  system2("/bin/rm /tmp/se_messages.*");


  system2("pkginfo -l                        > $SPDIR/pkginfo_l 2>&1");
  if (-x "/usr/bin/showrev") {
    system2("/usr/bin/showrev -p                        > $SPDIR/showrev_p 2>&1");
  }
  
}
  

sub t3s {
  my($devs) = @_; 
  &debug("\n-> MODULE: STORAGE ARRAY ");
  foreach my $dev (@$devs) {
     next if (index("t3,6120", $dev->{type}) < 0);
     &debug("  -> $dev->{type} $dev->{name}..");

     my $F = "$T3DIR/$dev->{name}";
     mkdir  $F, 0777;
     my $out = "$dev->{type}: $dev->{name} / $dev->{ipno}\n";
    
     if (!Util->ping($dev->{ipno})){
        &debug("ERROR: CANNOT PING $dev->{name}/$dev->{ipno}\n");
     } else {
        &debug(&telnet($F, $dev));
     }
  }

}

sub telnet {
  my($F, $dev) = @_;
  my $out;
  my $t= Net::Telnet->new(
	Timeout => 90,
        errmode => "return",
 	Prompt => '/:\/:<+[1-9]*[0-9]>$|word: $/'
         );

  return "Cannot telnet to $dev->{name}" if (!$t);

  if (!defined($t->open($dev->{ipno} ))) {
      return "Cannot telnet:open $dev->{name}/$dev->{ipno}";
  }
  $t->max_buffer_length(500000);

  $t->login('root',$T3PWD);

  if ($t->errmsg()) {
     return $t->errmsg();
  }
  $out .= &command($F, $t, "ver");
  if ($dev->{type} eq "6120") {
     $t->cmd("sun");
     $t->cmd("arrayservice");
  }
  my @oplist;
  @oplist = ("arp -a","tzset","date","set",".set",".ep info",
             "sys list",".sys list","sys stat","sys fc_topology",
             "fru list","fru myuid","fru stat","fru stat sys", "fru statistic",
             "vol list","vol stat","vol mode","refresh -s","route -r",
             "proc list","port list","port listmap",".loop stat", 
             "ntp","ntp -v","ntp stats","ls -l",
             "ls -l etc","ls -l web");

  my $max;
  foreach my $c (@oplist) {
     my $com = &command($F, $t, $c);
     if ($c eq "fru list") {
       my(@lines) = split(/\n/, $com);
       foreach my $l (@lines) {
         if ($l =~ /^\s*u(\d+)/) {
            my $u = $1;
            $max = $u if ($u > $max);
         }
       }
     }
     $out .= $com;
    
  }
  @oplist = ("volslice list","lun map list","lun wwn list",
             "lun perm list","hwwn list","hwwn listgrp");

  foreach my $c (@oplist) {
     $out .= &command($F, $t, $c);
  }
  my $list = $dev->{type} eq "t3" ? "d1-9" : "d1-14";

  $max = 2 if (!$max);
  my($u);
  for ($u=1; $u <= $max; $u++) {
    $out .= &command($F, $t, "disk version u$u$list");
    $out .= &command($F, $t, ".disk pathstat u$u$list");
    $out .= &command($F, $t, ".disk softerr u$u$list");
    $out .= &command($F, $t, ".disk harderr u$u$list");
    $out .= &command($F, $t, ".disk linkstat u$u$list path 0");
    $out .= &command($F, $t, ".disk linkstat u$u$list path 1");
  }

  return "";

}



sub command {
  my($F, $t, $com) = @_;

  my $file = $com;
  $file =~ s/\W/_/g;
  &debug2("    -> $com");
  my $out =<<EOF;

============================
|  COMMAND: $com
============================
EOF
  my @l   = $t->cmd($com);
  $#l = $#l -1 if ($#l > 0);
  $out .= join("", @l);
  open(O, ">$F/$file"); 
  print O $out;
  close(O);
  return $out;
}


# VICOMS

sub ves {
  my($devs) = @_;
  return if (-x "/opt/svengine/sduc/showmap");
  my $D = "/opt/svengine/sduc";
  my $l;
  &debug("\n-> MODULE: VE ");
  foreach my $dev (@$devs) {
     next if ($dev->{type} ne "ve");
     &debug("  -> $dev->{name}");
     my $out = "$dev->{type}: $dev->{name} / $dev->{ipno}\n";

     $out .=<<EOF;
============================
COMMAND: showmap -d $dev->{login}

EOF
     open(O, "$D/showmap -d $dev->{login}|");
     while ($l = <O>) {
        $out .= $l;
     }
     close(O);

     $out .=<<EOF;
============================
COMMAND: slicview view -d $dev->{login}

EOF
     open(O, "$D/slicview view -d $dev->{login}|");
     while ($l = <O>) {
        $out .= $l;
     }
     close(O);
     open(O, ">$DIR/ve/$dev->{name}");
     print O $out;
     close(O);
  }
}
  
  
sub debug {
  my($l) = @_;

  if ($DEBUG) {
    print "$l\n" ;
    open(O, ">>$DEBUGF");
    print O "$l\n";
    close(O);
    $debug_out .= "$l\n";
  }
}

sub debug2 {
  my($l) = @_;

  if ($DEBUG > 1) {
    print "$l\n" ;
    open(O, ">>$DEBUGF");
    print O "$l\n";
    close(O);
    $debug_out .= "$l\n";
  }

}



sub run1 {
  my($dir, $com) = @_;
  
  my @a = split(/\s+/, $com);
  my $fn = "$a[0]_$a[1]";

  &debug2("    -> $com");
  my $out =<<EOF;

============================
| COMMAND: $com
============================

EOF
   $out .= `$com`;
   open(O, ">$dir/$fn");
   print O $out;
   close(O);
   return $out;
}
  
  
  
