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

#  $Name:  $ 
#  $Id: Host.pm,v 1.28 2002/10/30 01:02:25 ccadieux Exp $

 
#             CREATION
####################################################
 
use Health;
use PDM;
use Carp;
use Data::Dumper;
use Report;
use strict;
use CIM::Instance;
use Message;
use Debug;
use TO;
  
use base 'Health';

sub revision {'$Revision: 1.28 $'}
 
sub new {
  my($hm, $pdm) = @_;

  my($self) = {pdm => $pdm};
  bless ($self, 'Health::Host');

# Specify each callback
#                            HM  Callback,  Filters
  $pdm->reportRequest($self, 'all_logic' , {FINAL => 1});
  $pdm->reportRequest($self, 'run_backup' , {category => Report::CAT_BACKUP} );
  $pdm->reportRequest($self, 'run_host' ,   {category => Report::CAT_HOST} );
  return $self;
}                     



# runs every time
#
sub run_host {
  my($hm, $report) = @_;
  my($run, $orep, $ompxio, $x);
  my($pdm)     = $hm->{pdm};
  my($renv)    = System->get_renv();
  my $Config   = PDM::ConfigFile->read();

  CIM->version("1.1");
  $DB::single = 1;

  my $rep     = $report->content();
  my $mpxio   = $rep->{mpxio};
  my $oreport = PDM->getOldReport($report->fileKey);
  my $orep    = $oreport->content()  if ($oreport);
  my $to      = TO->readExistingTopo();
  my $id      = $renv->{hostname};

  if (exists($rep->{'sp.ntc.status'})) {
     my $tran  = Transition->getTransition( {   
                                          key => $rep->{'sp.ntc.ip'} ,
                                         code => 'ntc',
                                        value => $rep->{'sp.ntc.status'},
                             transition_value => "CannotPing",
                                       repeat => '8h',
                                 });
     if ($tran =~ /IN/  || $tran =~ /OUT/) {
        my ($et, $desc, $sev);
        if ($tran =~ /IN/) {
          $et   = "agent.CommunicationLostEvent";
          $sev  = Message::SEVERITY_ERROR;
          $desc = "Lost Communication(oob) with Terminal-Concentrator /" . $rep->{'sp.ntc.ip'};
        } else {
          $et   = "agent.CommunicationEstablishedEvent";
          $sev  = Message::SEVERITY_NORMAL;
          $desc = "Regained Communication(oob) with Terminal-Concentrator /" . $rep->{'sp.ntc.ip'};
        }
        my $ev = CIM::Instance->new('NWS_CommunicationLostEvent', [
                  [ EventType       => $et  ],
                  [ EventId         => $pdm->getEventSequence  ],
                  [ Severity        => $sev ],
                  [ Actionable      => ($sev > 0) ],
                  [ Caption         => 'ntc' ],
                  [ Description     => $desc ]
                   ]);
        my $sd = Events->sourceDetector({ event => $ev });
        my $pertains = CIM::Instance->new('NWS_EventPertainsToSoftwareElement', [
                  [ Event      => $ev  ],
                  [ Element    => $sd->[0] ],
                    ]);
        my $ed = Message->new( { id   => {},
                            instances => [$ev, @$sd, $pertains ], severity  => $sev });
        $pdm->saveMessage($ed);

     }

  }
  return if (!$to); # cannot do ports or mpxio without a topo
#
# PORTS
#
  if ($oreport && exists($orep->{ports}) ) {
    my $hosts  = $to->hostList();
    my $oports = $orep->{ports};
    my $host1  = $hosts->[0];
    my $hbas   = $host1->portInfo();

    my $ports  = $rep->{ports};
    my $wwn = $renv->{hostname};
    foreach my $p (keys %$ports) {
       my $old = $oports->{$p} || "[undefined]";
       my $new = $ports->{$p} || "[undefined]";
       if ($old ne $new) {
         my($desc0) = "status of hba $p on $wwn changed from $old to $new";
         my $sev = ($new =~ /NOT/)? Message::SEVERITY_ERROR: Message::SEVERITY_GREEN;
         my $sign = ($new =~ /NOT/)? "M": "P";
         my $ev = $hm->alarmEvent( "", $report, $wwn, $desc0, undef, "$sign.hba", {noState => 1});
         my $p2 = $p;
         if ($p2 =~ /socal.*:(\d)$/) {
            $p2 = substr($p2,0,-2) . "sf\@$1,0:devctl";
         }
         my $found;
         for ($x=0; $x <= $#$hbas; $x++ ) {
             my $to_p = Util->ltrim($hbas->[$x]{path});
             if ($p2 eq $to_p) {
                $found = $x; last;
             }
             
         }
         if (defined($found)) {
            State->saveState("host", $wwn, "hba.$found", $wwn, $sev, $desc0, 1, $ev);
         }
       }
    }
  }

 
 
# ONLINE OFFLINE STANDBY

  if ($oreport) {
     $orep    = $oreport->content() ;
     $ompxio  = $orep->{mpxio};
  }
  foreach my $k (keys %$mpxio) {
     my($state, $desc) = split(/\t/, $mpxio->{$k});
     my $v = "MPXIO: $state on $desc";

     my($ostate, $odesc) = split(/\t/, $ompxio->{$k});
     if (!$oreport && ($state eq "OFFLINE")) {
       &saveMpx($to,"t3",$k, Message::SEVERITY_ERROR, $v);

     } elsif ($oreport && ($state ne $ostate)) {
        if ($state eq "OFFLINE") {
           &saveMpx($to,"t3",$k, Message::SEVERITY_ERROR, $v);
        } elsif ($state eq "ONLINE") {
           &saveMpx($to,"t3",$k, Message::SEVERITY_GREEN, $v);
        }
     }
  }
#
#  LUNS
# lun.VE.dev-rdsk-c7t2B00006022004188d7s2.statusA' => 'O.K.'
# lun.VE.dev-rdsk-c7t2B00006022004188d7s2.wwn' => 2900006022004188
# lun.T300.dev-rdsk-c14t50020F2300003EE5d0s2.statusA' => 'No UNIX Label'
# lun.T300.dev-rdsk-c14t50020F2300003EE5d0s2.wwn' => '50020f2000003ee5'


  if ($oreport) {
     $orep    = $oreport->content() ;

     # removed
     my $cimkey = $renv->{hostname};
     my $cnt;
     foreach my $key (keys %$orep) {
         if (substr($key,0,4) eq "lun." && substr($key, -3) eq "wwn" ) {
           my($a1, $type, $dev0, $a2) = split(/\./, $key);
           my $wwn    = $orep->{$key};
           if (!exists($rep->{"$a1.$type.$dev0.$a2"})) {
              my $dev = $Config->deviceByWWN($wwn, 4); # check only last 4 digits of wwn
              my $info =  "target=$dev->{type}:$dev->{name}/$dev->{ipno}" if ($dev);
              my $name = $renv->{hostname};
              $rep->{"$a1.$type.$dev0.statusA"} = "Missing";
              $hm->alarm($report, $orep, "host", "$a1.$type.$dev0", "statusA", $name, $name , $cimkey, "lun.status", {use_map_id => 1, info => $info }
                  );
              #State->saveState($dev->{type}, $dev->{key}, "e", $dev->{key}, 2, "inband comm lost", 0);
              last if ($cnt++ > 10);
           }
         }
     }
     # changed
     $cnt = 0;
     foreach my $key (keys %$rep) {
         if (substr($key,0,4) eq "lun." && substr($key, -3) eq "wwn" ) {
           my($a1, $type, $dev0, $a2) = split(/\./, $key);
           my $wwn    = $rep->{$key};

           foreach my $A ('A', 'B') {
             if (exists($rep->{"$a1.$type.$dev0.status$A"})
                   && exists($orep->{"$a1.$type.$dev0.status$A"}) ) {
                 my $dev = $Config->deviceByWWN($wwn, 4); # check only last 4 digits of wwn
                 my $name = $renv->{hostname};
                 my $info =  "target=$dev->{type}:$dev->{name}/$dev->{ipno}" if ($dev);
                 $hm->alarm($report, $orep, "host", "$a1.$type.$dev0", "status$A", $name, $name , $cimkey, "lun.status", {use_map_id => 1, info => $info}
                     );
                 last if ($cnt++ > 10);
             }
           }
         }
     }
  }
  # Check free space for our data files
  my $percent = $rep->{freeSpace}{varOptSunwstade};
  my $opercent = $orep->{freeSpace}{varOptSunwstade};
  $percent =~ s/%//;
  $opercent =~ s/%//;
   
  if ($percent >= 98 && $opercent < 98) {
     my($desc0) = "Detected SUNWstade at ${percent}% capacity";
     my $wwn = $renv->{hostname};
     $hm->alarmEvent( "", $report, $wwn, $desc0, 2, "disk_capacity");

  } elsif ($percent < 98 && $opercent >= 98) {
     my($desc0) = "Detected SUNWstade back to ${percent}% capacity";
     my $wwn = $renv->{hostname};
     $hm->alarmEvent( "", $report, $wwn, $desc0, 0, "disk_capacity_okay");
  }
}

sub saveMpx {
  my($to, $cat, $k, $sev, $desc) = @_;
  my($x,$y);
  my $L = $to->storageList();
  my $done = 0;
  for ($x=0; $x <= $#$L; $x++) {
     my $st = $L->[$x];
     next if ($st->{info}{type} ne $cat);
     my $k1 = $st->{info}{name};
     my $pi = $st->{portInfo};
     my $po = $st->{port};
     next if (!$pi);
     for ($y=0; $y <= $#$pi; $y++) {
       if ($pi->[$y]{PortWWN} eq $k) {
          my($t2, $k2) = split(/\:/, $po->[$y]);
          State->saveLinkState($cat, "$k1:$y", $t2, $po->[$y],
            $sev, $desc, undef, undef, undef, undef);
          $done = 1 ;last;
       }
     }
     last if ($done);
  }
        
  State->saveState($cat,  $k, "mpxio", undef, $sev, $desc, 0);
}



sub run_backup {
  my($hm, $report ) = @_;

  my($pdm)     = $hm->{pdm};
  CIM->version("1.1");
  $DB::single = 1;
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';
  my($rep)     = $report->content();
  my($packages) = $rep->{showrev};

  my($oreport) = PDM->getOldReport($report->fileKey);

  my($orep, $desc, $data, $run, $disco, $opackages, $obackup, $x);


#
# BACKUP
#
  if (!$oreport) {
     $run = 1;
  } else {
     $orep  = $oreport->content();
     if ($orep->{backup_config} ne $rep->{backup_config}) {
        $run = 1;
     }
  }
  if ($run) {
       my $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => "host.backup"  ],
                  [ EventId     => $pdm->getEventSequence  ],
                  [ MgmtLevel   => $mgmtLevel ],
                  [ Description => "NS Agent backup"],
                  [ Data        => $rep->{backup_config}]
                         ]);

       my $sd = Events->sourceDetector({ event => $ev , host => 1, rep => $rep});
 
       my $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $sd->[3]]
                    ]);

       my $ed = Message->new( {  id        => $report->id,
                            instances => [$ev, @$sd , $pertains],
                            severity  => Message::SEVERITY_NORMAL });

       $pdm->saveMessage($ed);
  }

#
#  PACKAGES
#
  $run = 0;
  if (!$oreport) {
     $desc  = "New Patch and Package Information generated";
     $disco = "D";
     foreach my $k (sort keys %$packages) {
       next if (substr($k,0,5) ne "patch" && substr($k,0,5) ne "packa");
       $data .= "ADD=$k|$packages->{$k}\n";
     }
     $run = 1; 
  } else {
     $desc  = "Patch and/or Package Information has changed:";
     $orep  = $oreport->content();
     $opackages =  $orep->{showrev};
     $disco = "A";
     foreach my $k (keys %$packages) {
        next if (substr($k,0,5) ne "patch" && substr($k,0,5) ne "packa");
        if (!$opackages->{$k}) {
           $data .= "ADD=$k|$packages->{$k}\n";
           $run = 1;
        } elsif ($packages->{$k} ne $opackages->{$k}) {
           $data .= "UPDATE=$k|$packages->{$k}\n";
           $run = 1;
        }
     }
     foreach my $k (keys %$opackages) {
        next if (substr($k,0,5) ne "patch" && substr($k,0,5) ne "packa");
        if (!$packages->{$k}) {
           $data .= "DELETE=$k|$opackages->{$k}\n";
           $run = 1;
        }
     }
   }
   if ($run) {
       my $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => "host.PatchInfo"  ],
                  [ EventId     => $pdm->getEventSequence  ],
                  [ Description => $desc],
                  [ MgmtLevel   => $mgmtLevel ],
                  [ Data        => $data]
                         ]);

       my $sd = Events->sourceDetector({ event => $ev , host => 1, rep => $rep});
 
       my $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $sd->[3]],
                  [ DiscoveryType => $disco],
                    ]);

       my $ed = Message->new( {  id        => $report->id,
                            instances => [$ev, @$sd , $pertains],
                            severity  => Message::SEVERITY_NORMAL });

       $pdm->saveMessage($ed);
   }
}

sub all_logic {
  my($hm ) = @_;
  my($pdm) = $hm->{pdm};
  my($ev, $ed, $x, $pertains , $sd);
  my($HB) = 'heartbeat';
  CIM->version("1.1");
  my $renv = System->get_renv();
  $DB::single = 1;

#
# RUNS after all health ran.
#
 if ($pdm->getEventCount > 0) {
     Timer->resetTimer($HB);
 } else {
     my($hb_delay) = $renv->{heartbeat} || 24; # hours
     $hb_delay *= 60;
     if (Timer->getTimer($HB) > $hb_delay) { #it's been a day with no transmission.
        Timer->resetTimer($HB);
        $ev = CIM::Instance->new('NWS_HeartbeatEvent', [
                  [ EventType   => 'agent.HeartbeatEvent' ],
                  [ EventId     => $pdm->getEventSequence  ],
                  [ MgmtLevel   => "" ],
                  [ Interval    => 24 * 60],
                         ]);
        $sd = Events->sourceDetector({ event => $ev });
        $pertains = CIM::Instance->new('NWS_EventPertainsToSoftwareElement', [
                  [ Event       => $ev  ],
                  [ Element     => $sd->[0] ],
                    ]);
        $ed = Message->new( { id   => {},  # no associated report
                            instances => [$ev, @$sd, $pertains ],
                            severity  => Message::SEVERITY_NORMAL });
        $pdm->saveMessage($ed);
     }
 }

# GET ALL SYSTEM ERRORS AND SEND AS EN EVENT.
 my($sys_errs) = Debug->get_system_errors();
 my $len = length($sys_errs);
 if ($len > 2000) {
   $sys_errs = substr($sys_errs,0,2000) . "\ntotal-size=$len";
 }

 if ($sys_errs) {
    $ev = CIM::Instance->new('NWS_Event', [
              [ EventType   => 'agent.AlarmEvent' ],
              [ EventId     => $pdm->getEventSequence  ],
              [ Severity    => Message::SEVERITY_WARNING ],
              [ MgmtLevel   => "" ],
              [ Data        => $sys_errs   ],
              [ Target      => $renv->{hostname} ],
              [ Description => substr($sys_errs,0,100) . ":"] ,
                     ]);
    $sd = Events->sourceDetector({ event => $ev });

    $pertains = CIM::Instance->new('NWS_EventPertainsToSoftwareElement', [
              [ Event           => $ev  ],
              [ Element         => $sd->[0] ],
                ]);

    $ed = Message->new( { id   => { deviceName => $renv->{hostname} },
                        instances => [$ev, @$sd, $pertains ],
                        severity  => Message::SEVERITY_WARNING});
    $pdm->saveMessage($ed);
  }
} 

1;
