package Agent::SP;
#<copyright>
# ----------------------------------------------------------
# Sun Proprietary/Confidential Code
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>

#  $Name: bld21_017 $ 
#  $Id: SP.pm,v 1.14 2005/05/13 20:45:54 edunning Exp $
use Agent;
use Carp;
use Report;
use TO;
use vars qw($AUTOLOAD);
use System;
use base 'Agent';
use strict;

sub isSelectable {"Service Processor"}
sub revision {'$Revision: 1.14 $'}

use vars qw ($SEQUENCER $SEQ_ERR $MGMT_DIR $DB);

$MGMT_DIR = "/opt/se6x20";

sub new {
  my($self) = Agent->new();

  bless ($self, 'Agent::SP');
  return $self;
}


sub RUN {
  my($agent, $static_list, $pass) = @_;
  my($showrev, $backup, $report);
  my $renv = System->get_renv();
  my $mgmtLevel = "C";
  my($log_err, $lines);
  $DB::single = 1;
  my $processed_list = [];

  # RUN ONCE A DAY ONLY
  if (Timer->isXdays('readPatch', 2)) {

    $report = {};
    $agent->showrev($report);
    $agent->backup($report);

    $report->{"id.mgmtLevel"} = $mgmtLevel;

    $agent->addIdentification($report);

    my $id = {  
              deviceName  => System->hostid(),
              display     => $renv->{hostname},
              active      => "Y",
              logFile     => "",
              class       => "backup",
              name        => $renv->{hostname},
              category    => Report::CAT_BACKUP,
              ip          => System->hostname(),
           };

    my $new_rep = Report->new($id, $report , undef);
    require Health::Host;
    Health::Host->run_backup($new_rep);
    PDM->saveReport($new_rep);

  }
  #
  # RUN SAN when there is a 'host' entry in the static_list
  #
  my $run;
  foreach my $d (@$static_list) {
     if ($d->{key} eq $renv->{hostname}) {
        $run = 1; last;
     }
  }
  return [] if (!$run);

  Timelapse->start("sp:$renv->{hostname}");

  Debug->print1("-> SP : Reading SP $renv->{hostname}");
  # 
  # INSTRUMENTATION
  #
  my($id);
  my $report = $agent->INSTRUMENTATION();

  my $warn_lines = $report->{"info.uulog"};

  if ($#$warn_lines >= 0) {
      $id = {
            deviceName  =>  System->hostid(),
            active      => "Y",
            logFile     => "uulog",
            display     => $renv->{hostname},
            name        => $renv->{hostname},
            class       => "server.sp",
            category    => Report::CAT_MESSAGE,
            ip          => "",
      };
      $report->{"id.name"} = $renv->{hostname};
      my $new_rep = Report->new($id, $report , $warn_lines, Report::STATUS_DONT_SAVE);
      require Health::Message;
      my $broke_list = Health::Message->all_logic($new_rep);
  }

  
  my $problems = PDM->get_last_event();

  my $id = {     
              deviceName  => System->hostid(),
              display     => $renv->{hostname},
              active      => "Y",
              logFile     => "",
              class       => "server.sp",
              name        => $renv->{hostname},
              category    => Report::CAT_SP,
              ip          => System->hostname(),
        };

  my $new_rep = Report->new($id, $report , undef);

  require Health::SP;
  Health::SP->run_host($new_rep);

  PDM->saveReport($new_rep);

  my $device = ConfigDev->new({ type   => "sp",   key  => $renv->{hostname}, 
                                active => "Y",    name => $renv->{hostname},
                             });
  my ($broke, $abort) = $agent->new_events($problems, $device, 1);
  push(@$processed_list, $device);

  Timelapse->stop("sp:$renv->{hostname}");
  return $processed_list;
}


sub INSTRUMENTATION {
  my($agent) = @_;

  my $renv = System->get_renv();
  my $mgmtLevel = "C";
  my $device = { type => 'sp', key => System->hostid(),
                 name => $renv->{hostname} };

  return Report->readTest($device) if (System->get_testMode());
  my($err, $cache1, %ENC, @HBA, %MPX);
  my $report = {};
  $agent->readFreeSpace($report);
  $agent->agent_patches($report);

  $report->{"id.ipno"} = System->get_ipno();
  $report->{"id.mgmtLevel"} = $mgmtLevel;

  $agent->addIdentification($report);

  if ($renv->{solution} eq "se") {
    require Provider::SSRR;
    if (-x $Provider::SSRR::S2S) { # service processor related report
      my $ping = Util->ping("10.0.0.3", "45") ? "OK":"CannotPing";
      $report = {'info.ntc.ping' => $ping, 'info.ntc.ip' => '10.0.0.3' };
    }
    $report->{'id.solution_model'} = $renv->{solution_model};
    $report->{'id.sp_version'} =    System->get_se_version();
    my $sec = System->getPackageInfo("", "SUNWsecfg", "VERSION");
    $report->{'id.secfg_version'} = Util->ltrim($sec);
    $report->{'id.seuucp_login'} =  Util->uucpLogin();
  
  }

  if ($renv->{solution} eq "se2") {
     $report->{'id.sp_version'} =    System->get_se_version();
     foreach my $e ('firewall','ntc') {
       my $h = $renv->{hostname} . "-$e";
       my $ping = Util->ping($h) ? "OK" : "CannotPing";
       if ($ping ne "OK") {
         $ping = Util->ping($h, 20) ? "OK" : "CannotPing";
       }
       $report->{"info.$e.ping"} = $ping;
       $report->{"info.$e.ip"}   = $h;
     }
    if (0) {
     my $inv = Inventory->readInventory();
     my $devs = $inv->getKeys();
     foreach my $k (keys %$devs) {
       my $d = $devs->{$k};
       if ($d->{type} eq "sp") {
          my $frus = $d->frus();
          foreach my $f (keys %$frus) {
             my $val = $frus->{$f};
             foreach my $v (keys %$val) {
               $report->{"SP.$f.$v"} = $val->{$v};
             }
          }
          $report->{"SP.sp.sysRevision"} = $d->{sysRevision};
          $report->{"SP.sp.hostinfo"}    = $d->{hostinfo};
          $report->{"SP.sp.ipno"}        = $d->{ipno};
          last;
       }
     }
    }

     $report->{"info.power_sequencer.status"} = $SEQUENCER;
     $report->{"info.power_sequencer.error"}  = $SEQ_ERR;
     $report->{"info.uulog"}                  = $agent->uulog($report); 

     my ($err,$drive) = Util->run_command(
                          "/usr/sbin/cfgadm -la",
                          "cfgadm.txt", 20);


      foreach my $l (@$drive) {
         if ($l !~ /Ap_Id/) {
            my(@a) = split(/ +/, $l);
            my $loc = $a[0];
            $loc =~ s/\//_/g;
            $report->{"drive.$loc.slot"} = $a[2];
            $report->{"drive.$loc.condition"} = $a[4];
         }
      }
  }
  return $report;

}

sub uulog {
   my($class, $report) = @_;
   my $renv = System->get_renv();
   my ($l, $tell, $line);

   my $warn_lines = [];
   my $file = "/var/uucp/.Log/uucico/ichabod";
   my $cache = RasDB->cache(); 
   my $seek  = $cache->{"uulog.seek"};

   if (!open(FILE_F2, $file)) {
      return $warn_lines;
   }

   my $size = (stat($file))[7];
   if ($seek) {
      if ($seek < $size) {
         seek(FILE_F2, $seek, 0);

      } elsif ($seek == $size) {
         close(FILE_F2);
         return $warn_lines;
      }
   }
   for ($tell = tell(FILE_F2); $line = <FILE_F2>; $tell = tell(FILE_F2)) {
       chop($line);
       my @a = split(/\s+/, $line);
       my $ix = substr($a[2],0,1) eq "(" ? 2:3;
       my @t = split(/[\/\-\:,]/, substr($a[$ix], 1 , -1));
       my $time = sprintf("%2.2d-%2.2d %2.2d:%2.2d:%2.2d", @t);

       my $key = "sp:" . System->hostid();
       if ($line =~ /CONN FAILED/) {
          my($level, $cnt, $desc, $mins, $thr) = Thresholds->test("uucp","CONN_FAILED",1,1);
          if ($level eq "W") {
             $warn_lines->[2]{$key}{egrid}  = "uulog";
             $warn_lines->[2]{$key}{action} = 1;
             $warn_lines->[2]{$key}{count}++;
             my $t1 = "in $mins mins" if ($mins && $thr > 1); 
             $warn_lines->[2]{$key}{line} = "Received $cnt '$desc' messages $t1: $line";
             $warn_lines->[2]{$key}{name} = $renv->{hostname};
             $warn_lines->[2]{$key}{ip}   = Util->name2ip();
          }
       }
       
   }
   close(FILE_F2);
   $cache->{"uulog.seek"} = $tell;
   return $warn_lines;
}



##############################
# SP : Maserati
##############################

sub call_sequencer {
   my($class, $renv) = @_;

   my $command    = "$MGMT_DIR/tools/checkPower";
   
   my($renv) = System->get_renv();
   my($TO) = $renv->{'timeout.power_seq'} || 480;

   my($err,$com) = Util->run_command( $command, "login" ,$TO);

   if ($com->[0] eq "") {
     if($err =~ /Timeout/){
        return "ERROR: Timeout for checkPower\n";
     }else{
        return "ERROR : checkPower returned nothing!";
     }
   } else {
     return $com->[0];
   }
}


# return SKIP_value:   0=OK/NOT_INSTALLED or 1=PROBLEM
# called early on by rasagent

sub sequencer_status {
  my($class) = @_;
  my $renv = System->get_renv();
  if (($renv->{solution} ne "se2") || (!-f "$MGMT_DIR/PSDATA/PS")){
    $SEQUENCER = "POWER_MGMT_NOT_ENABLED"; #checkPower will someday return this 
    $SEQ_ERR   = "POWER_MGMT_NOT_ENABLED"; #I luv global variables!!!
    $class->updateReport();    
    return 0; 
  }

  $SEQ_ERR = "";
  $SEQUENCER = $class->call_sequencer($renv);

#  ON DOWN REMOTE_SEQUENCER_ERROR  UNKNOWN

  if ($SEQUENCER =~ /DOWN/) {
     $SEQUENCER = "OFF";
     if (Debug->errNoRepeat(ERROR => "rack_$renv->{solution_model}", 8,
               "Power Sequencer on '$renv->{hostname}' is OFF")) {
          Util->run_command("/opt/se6x20/bin/vmcfg status -t rack -s DOWN",
                            "vmfcfg", 30, { cache => 0 } );
     }
     $class->updateReport();
     return 1;

  } elsif ($SEQUENCER =~ /ERROR/ || 
           $SEQUENCER =~ /UNKNOWN/ || 
           $SEQUENCER =~ /LOST_COMM/ ) {
    $SEQ_ERR   = $SEQUENCER;
    if($SEQUENCER =~ /Timeout/){
       $SEQUENCER = "ERR_TIMEOUT";
    }

  } elsif ($SEQUENCER =~ /ON/) {
     $SEQUENCER = "ON";
  }
  $class->updateReport();
  return 0;
}

#
# UPDATE statur/error on SP and SE2 reports
#
sub updateReport {
  my($class) = @_;
  return;
}







sub readFreeSpace {
  my($class, $report) = @_;
  my($renv) = System->get_renv();
  my($TO) = $renv->{'timeout.luxadm'};
  my $df = System->find_command("df");

  my ($err, $data) = Util->run_command("$df -k /var/opt/SUNWstade","cap.txt", $TO);
  foreach my $l (@$data) {
     next if ($l !~ /^\/dev/);
     my($path, $kbyts, $used, $avail, $capacity, $mount) = split(/\s+/, $l, 6);
     $report->{"freeSpace./var/opt/SUNWstade"} = $capacity;
  }
  my ($err, $data) = Util->run_command("$df -k","cap.txt", $TO);
  foreach my $l (@$data) {
     my($path, $kbyts, $used, $avail, $capacity, $mount) = split(/\s+/, $l, 6);
     next if ($path eq "Filesystem");
     $report->{"freeSpace.$path|$mount"} = $capacity;
  }
}


sub backup {
  my($agent, $report) = @_;
  my($out, $l);
  return {} if (Util->findMaster() ) ;

  open(O, System->get_home() . "/DATA/rasagent.conf");
  while ($l = <O>) {
     $out .= " " . $l;
  }
  close(O);
  $report->{"backup_config"} = $out;

  my $D = System->get_home() . "/DATA/topo";
  $report->{"backup.master_topo.age"} = Util->getFileAge("$D/MERGE-MASTER");
}


sub agent_patches {
  my($agent, $report) = @_;
  my ($data, %R, $out);

  my $DIR = System->get_home() . "/docs";
  opendir(O, $DIR);
  my @files = readdir(O); closedir(O);
  foreach my $f (@files) {
     next if ($f !~ /ReleaseNotes.+-.+/);
     my(@a) = split(/\./, $f);
     $out .= "$a[1]|";
  }
  $report->{"id.patches.local"} = $out;
}

   
sub showrev {
  my($agent, $report) = @_;
  my($patch, $ob, $req, $inc, $pack);
  my %R ;

  my ($err, $com) = Util->run_command("/usr/bin/showrev -p", "test", 100);

  foreach my $l (@$com) {
     if ($l =~ /Patch: (.+) Obsoletes: (.*) Requires: (.*) Incompatibles: (.*) Packages: (.*)/) {
       $patch = $1;
       $ob    = $2;
       $req   = $3;
       $inc   = $4;
       $pack  = $5;
       $pack =~ s/ //g;
       $req  =~ s/ //g;
       $report->{"showrev.patch.$patch"} = "$ob|$req|$inc|$pack";
     }
  }
 
  ($err, $com) = Util->run_command("/usr/bin/pkginfo -l", "test", 100);
  my($sys, $pk, $name, $vers, $install);

  foreach my $l (@$com) {
     my(@a) = split(/:  /, $l, 2);
     $a[0] = Util->ltrim($a[0]);

     if ($a[0] eq "PKGINST") {
        $pk = $a[1];

     } elsif ($a[0] eq "NAME") {
        $name = $a[1];

     } elsif ($a[0] eq "CATEGORY") {
        $sys = $a[1];

     } elsif ($a[0] eq "VERSION") {
        $vers = $a[1];

     } elsif ($a[0] eq "INSTDATE") {
        $install = $a[1];
        $report->{"showrev.package.$pk"} = "$sys|$vers|$install|";    # $name";
     }
  }
}

sub FRUS {
  my($class, $r, $name) = @_;
  my($v) = $r->{_value};
  my @FRUS;
  my $renv = System->get_renv();
  my $devtype = "SP";

   my($rev, $st) = System->read_release();
   push(@FRUS, [ $name , $devtype, $devtype, $renv->{hostname}, "SUN",
                      System->model(), System->hostid(),
                      $rev, "N/A" ]);
     
  return \@FRUS;
}




sub REPORT {
  my($class, $host, $r, $arg) = @_;
  
  my($renv, $devs, $hosts,$notifs, $Config) = PDM::ConfigFile->read();

  my $SLICE = Util->deserialize("slice_map");
  my $typ   = "SP";

  my $line1;
  if ($r->value("id.solution_model")) {
    $typ = $r->value("id.solution_model") ."-SP";
    $line1 = "
     <tr><td bgcolor=$Style::LIGHT width=40% align=right>Sun Series: <td>&nbsp;" . 
        $r->value('id.solution_model')  . "</td>
     <tr><td bgcolor=$Style::LIGHT width=40% align=right>SUNWsecfg Version: <td>&nbsp;" . $r->value('id.secfg_version')  . 
     "<tr><td bgcolor=$Style::LIGHT width=40% align=right>SP Version: <td>&nbsp;" . $r->value('id.sp_version')  ;
  }
  my $out = "<table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
  <tr><td colspan=2 bgcolor=$Style::DARK><font color=white><b>$typ $host";
  $out .= $line1;

  my $to = TO->readExistingTopo($arg->{host});
  if ($to) {
     my $node = $to->nodeByName("sp:$arg->{host}");
     my $ip = $r ? $r->value("id.ipno") : $node->{info}{ipno};
     if ($node) {
       my $ports = $node->portInfo();
       $out .= "
        <tr><td bgcolor=$Style::LIGHT width=40% align=right>IP: <td>$ip&nbsp;</td>
        <tr><td bgcolor=$Style::LIGHT width=40% align=right>Model: <td>$node->{info}{model}</td>";
       $out .= "<tr><td colspan=2><font color=red><b>Warning:</b>
                  $node->{info}{errors}</td>"  if ($node->{info}{errors});

       $out .= "</table>
      <table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
       <tr bgcolor=$Style::LIGHT>
       <th>#</th>
       <th>Reg</th>
       <th>Slot</th>
       <th>Port-WWN</th>
       ";
       my ($x);
       for ($x=0; $x <= $#$ports; $x++) {
         my $p = $ports->[$x];
         my($p1, $p2, $p3) =  split(/:/, $p->{BoardSlotPort});
         my ($wwn, $bsp);
         if ($p->{PortWWN} !~ /^0*$/) {
            $wwn = $p->{PortWWN};
         } else {
            next;
         }
         my $pp = $p->{RegisterName};$pp =~ s/\-/- /;
         my $bg = ($p->{Mode} eq "online") ? "<b><font color=blue>":"";
         $out .= "<tr><td>$x</td>
                    <td>$bg$pp</td>
                    <td>Board:$p1 Slot:$p2 Port:$p3</td>
                    <td>$bg<small>$wwn</td>
               ";
       }
       $out .= "<tr><td colspan=5>&nbsp;No HBA found!</td>" if ($#$ports < 0);
       $out .= "</table>";
     } else {
       $out .= "</table>";
     }
  } else {
    $out .= "</table>";
  }
  if ($r) {
    my($v) = $r->{_value};
    $out .= " <table border=0><tr><td></table>";

    my ($k, $x);

# FREE SPACE
    my $first = 1;
    foreach my $x (sort keys %$v) {
        if (substr($x,0,10) eq "freeSpace.") {
           next if ($x =~ /\w{30}/);
           if ($first) {
              $out .= "
               <table border=0><tr><td></table>
                <table border=1 width=$Style::WIDTH bgcolor=white cellspacing=0 cellpadding=1>
                <tr bgcolor=$Style::LIGHT><td><b>&nbsp;Filesystem<th>Mounted<th>Capacity";
              $first=0;
           }
           my ($fs,$mounted) = split(/\|/, substr($x,10));
           $fs =~ s/:/: /;
            
           $out .= "<tr><td>&nbsp;$fs<td>&nbsp;$mounted<td align=right>$v->{$x}&nbsp;</td>";
        }
    }
    $out .= "</table>";

  # Attached devices
    my $first = 1;
    foreach my $x (sort keys %$v) {
        if ($x =~ /^drive\.(usb0.*)\.condition/) {
           my $ap_id = $1;
           if ($first) {
              $out .= "
               <table border=0><tr><td></table>
                <table border=1 width=$Style::WIDTH bgcolor=white cellspacing=0 cellpadding=1>
                <tr bgcolor=$Style::LIGHT><td><b>&nbsp;Ap_Id<th>Receptacle<th>Condition";
              $first=0;
           }
           my $real_name = $ap_id;
           $real_name =~ s/\_/\//g;
           $out .= "<tr><td>&nbsp;$real_name<td>&nbsp;$v->{\"drive.$ap_id.slot\"}<td align=right>$v->{$x}&nbsp;</td>";
        }
    }
    $out .= "</table>";

  }

  $out .= "&nbsp;<p>&nbsp;";
  return $out;
}
    
  1;
