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

#Name:  $
#  $Id: T3.pm,v 1.43 2002/10/29 01:21:58 ccadieux Exp $


use base 'Health';
use NWS::T3;
use Ilist;
use Message;
use Catalog;
use Report;
use System;
use Events;
use strict;
use Debug;

sub revision {'$Revision: 1.43 $'}

sub new {
  my($hm, $pdm) = @_;

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

# Specify each callback
#                            HM  Callback,  Filters
  $pdm->reportRequest($self, 'all_logic' , {category => Report::CAT_T3});
  return $self;
}

#####################################################

sub all_logic {
  my($hm, $report) = @_;
  my($pdm) = $hm->{pdm};
  my($ev, $ed, $pertains, $x ,$y, $contain, $sd);
  my($orep, $key);
  my($rep)     = $report->content;
  my($oreport) = PDM->getOldReport($report->fileKey);
  my($ip)      = $report->id('ip');
  $DB::single = 1;
  my $wwn      = $report->id('deviceName');
  my($id)      = $report->id('display');
  my($shortid) = $report->name();
  my($log)     = $report->log();
  my($renv)    = System->get_renv();
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';
  if (!$wwn) {
     Debug->errNoRepeat(T3_NO_KEY => $ip, 24, 
                        "This T3 ($ip) cannot be identified");
     return;
  }

  CIM->version("1.1");

  my $invalidate_catalog = 0;

  if ($hm->connectionEvent($wwn, $report, {method => 3} )) {  # IB / OOB
     return;
  }
  my($audit); 
  my($freq) = $renv->{audit_freq} || 7;
  if (!$oreport || ($audit = Timer->isXdays("Audit$wwn", $freq)) eq "YES" ) {  # new t300 or audit time.
     my($etype) = $audit ? "t3.AuditEvent" : "t3.DiscoveryEvent";
     my($title) = $audit ? "Auditing a":"Discovered a new";
     my($dt)    = "A" if (!$audit);

     $invalidate_catalog = 1;

     $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => $etype  ],
                  [ Target      => $wwn    ],
                  [ TargetName  => $id     ],
                  [ SourceIP    => $ip     ],
                  [ MgmtLevel   => $mgmtLevel ],
                  [ EventId     => $pdm->getEventSequence  ],
                  [ Description => "$title T3 called $id"],
                         ]);

     $sd = Events->sourceDetector({ event => $ev , host => 1, rep => $rep});
      
     my($p) = NWS::T3->newSystem($rep);

     $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $p->[0] ],
                  [ DiscoveryType => $dt],
                    ]);
     my($monitors) = CIM::Instance->new('NWS_AgentMonitors', [
                  [ Agent       => $sd->[0]  ],
                  [ Element     => $p->[0] ],
                    ]);

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

     $pdm->saveMessage($ed);

     if ($audit) {  # dump stats.

        $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => 't3.Statistics'  ],
                  [ Target      => $wwn    ],
                  [ TargetName  => $id     ],
                  [ SourceIP    => $ip     ],
                  [ MgmtLevel   => $mgmtLevel ],
                  [ EventId     => $pdm->getEventSequence  ],
                  [ Description => "Statistics about T3 $id :"],
                  [ Data        => Util->nnl($rep->toString('system.'))],
                         ]);

        $sd = Events->sourceDetector({ event => $ev });

        my($system_key) = CIM::Key->new( ['NWS_System', 
                    'Name'            =>$rep->get('id.wwn'),  
                    CreationClassName => 'NWS_System']);

        $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $system_key ],
                    ]);

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

        $pdm->saveMessage($ed);

     }
#    sysCtime,Fri Oct 26 09:48:27 2001
     my $now    = Util->get_today();  # YYYY-MM-DD HH:MM:SS
     my $t3time = $rep->{'system.sysCtime'};
     if ($t3time ) {
       my($t3_day, $t3_hour, $t3_min, $t3_sec, $t3_zone, $t3_year) = split(/[ :]/, substr($t3time,8));
       $t3_year = $t3_zone if ($t3_zone =~ /^20/);
       my $t3_month = $Util::MTH{substr($t3time, 4,3)};
       if ($t3_year =~ /\d\d\d/ && $t3_sec =~ /\d+/ && $t3_min =~ /\d+/ ) {
         my $now_mins = Util->julianMins(substr($now,0,4), substr($now,5,2),
                               substr($now,8,2), substr($now,11));
         my $t3_mins = Util->julianMins($t3_year,$t3_month, $t3_day,
                               substr($t3time,11,8));

         if (abs($t3_mins - $now_mins) > 1) {
            my $tt = "$t3_year-$t3_month-$t3_day " . substr($t3time,11,8);
            $hm->alarmEvent("", $report, $wwn, 
           "Time of T3 $id is different from host: T3 time='$tt', Host time='$now'", 0, "time_diff", {severity => 1} );
         }
       }      
     }
  }

  $orep = ($oreport)? $oreport->content() : $rep; # same report if new disco.

  $hm->locationChangeEvent($report, $rep, $orep, $wwn);

  my($physicalFrame) = CIM::Key->new( ['CIM_PhysicalFrame',   # key of the frame
                        Tag               => $rep->get("id.wwn") ,
                        CreationClassName => 'CIM_PhysicalFrame' ]);

  my $reboot  = $rep->{'system.sysLastRestart'};
  my $oreboot = $orep->{'system.sysLastRestart'};
  my $reboot_month = $Util::MTH{substr($reboot, 4,3)};
  my $oreboot_month = $Util::MTH{substr($oreboot, 4,3)};

  if ("$reboot$oreboot" =~ /\d+:\d+:\d+.*(20\d+).*\d+:\d+:\d+.*(20\d+)/) {
      my $reboot_year = $1;
      my $oreboot_year = $2;
      my $reboot_mins   = Util->julianMins($reboot_year, $reboot_month, 
                            substr($reboot,8,2), 
                            substr($reboot,11,8) );
      my $oreboot_mins  = Util->julianMins($oreboot_year, $oreboot_month, 
                            substr($oreboot,8,2), 
                            substr($oreboot,11,8) );
      if (abs($reboot_mins - $oreboot_mins) > 5) {
        $hm->alarmEvent("", $report, $wwn, 
          "System reboot for T3 $id changed from '$oreboot' to '$reboot'", 
           0, "system_reboot", {severity => 1} );
      }
  }

  my($CTRL) = $rep->get('controller.count');
# check if disks were replaced or their state has changed.
  my($comp);
  for ($x=1; $x <= $CTRL; $x++) {
  my($oserial, $nserial, $oport, $nport);
# CONTROLLER (1)
     $comp = "controller.u${x}ctr";
     $oserial = NWS::T3->getKey($orep, $comp); 
     $nserial = NWS::T3->getKey($rep, $comp);  
     $oport   = lc($orep->{"port.u${x}p1.portWWN"});
     $nport   = lc($orep->{"port.u${x}p1.portWWN"});

     if (!$nserial && defined($nserial)) {# move the key from old to new
         NWS::T3->copyKey($comp, $orep, $rep);
         $nserial = NWS::T3->getKey($rep, $comp);  
     }

     if ($oserial eq $nserial) {
         my $S = $nport || "$wwn.$comp";
         $hm->stateEvent($comp, $report, $rep, $orep, 'CIM_Card', $S, $wwn);
     } else {
         if ($oserial) {
           $hm->removeCompEvent($comp,$physicalFrame, $report, 'CIM_Card',$oport, $wwn,
               {desc => "($oserial -> $nserial)"} );
         }
         if ($nserial) {
           my($ctrl) = NWS::T3->newController($rep, $comp, $x);
           $hm->insertCompEvent($comp,$physicalFrame,$report, $ctrl, $nport, $wwn, 
               {desc => "($oserial -> $nserial)"}  );
           $invalidate_catalog = 1;
         }
     }

# POWER SUPPLY (2)
     for ($y=1; $y <= 2; $y++) {
        $comp = "power.u${x}pcu$y";
        $oserial = NWS::T3->getKey($orep, $comp); 
        $nserial = NWS::T3->getKey($rep, $comp);  

        if (!$nserial && defined($nserial)) {# move the key from old to new
           NWS::T3->copyKey($comp, $orep, $rep);
           $nserial = NWS::T3->getKey($rep, $comp);  
        }
        if ($oserial eq $nserial) {
           $hm->stateEvent($comp, $report, $rep, $orep, 'CIM_PhysicalPackage', $nserial, $wwn);

           if ($orep->{"$comp.fruPowerBatState"} eq "refreshing" &&
               $rep->{"$comp.fruPowerBatState"} eq "fault") {
               $hm->alarmEvent("", $report, $wwn, "The state of $comp.fruPowerBatState on T3 $id went from refreshing to fault", 
                       0, "M.$comp.fruPowerBatState", {severity => 1} );
           } else {
              $hm->alarm($report,  $orep, "T3", $comp, "fruPowerBatState", $shortid, $id, $wwn);
           }
           foreach my $el ('Fan1State','Fan2State','PowOutput','PowTemp') {
              $hm->alarm($report,  $orep, "T3", $comp, "fruPower$el", $shortid, $id, $wwn);
           }

        } else {
           if ($oserial) {
             $hm->removeCompEvent($comp, $physicalFrame, $report, 'CIM_PhysicalPackage',$oserial, $wwn);
           }
           if ($nserial) {
             my($part) = NWS::T3->newPowerUnit($rep, $comp);
             $hm->insertCompEvent($comp,$physicalFrame,$report, $part, $nserial, $wwn);
             $invalidate_catalog = 1;
           }
        }
     }
# LOOP CARDS (2)
     for ($y=1; $y <= 2; $y++) {
        $comp = "loopcard.u${x}l$y";

        $oserial = NWS::T3->getKey($orep, $comp); 
        $nserial = NWS::T3->getKey($rep, $comp);  

        if (!$nserial && defined($nserial)) {# move the key from old to new
           NWS::T3->copyKey($comp, $orep, $rep);
           $nserial = NWS::T3->getKey($rep, $comp);  
        }

        if ($oserial eq $nserial) {
           $hm->stateEvent($comp, $report, $rep, $orep, 'CIM_Card', $nserial, $wwn);
           my $cable  = ($x==1)? 2: 1;
           if ($CTRL > 1) {
             $hm->alarm($report, $orep, "T3", $comp, "fruLoopCable${cable}State", $shortid, $id, $wwn);
           }

        } else {
           if ($oserial) {
             $hm->removeCompEvent($comp,$physicalFrame,$report, 'CIM_Card',$oserial, $wwn);
           }
           if ($nserial) {
             my($part) = NWS::T3->newLoopCard($rep, $comp);
             $hm->insertCompEvent($comp,$physicalFrame,$report, $part, $nserial, $wwn);
             $invalidate_catalog = 1;
           }
        }
     }
# DISKS (9)
     my $diskTotal = $rep->get('disk.count') || 9;
     for ($y=1; $y <= $diskTotal; $y++) {
        $comp = "disk.u${x}d$y";

        $oserial = NWS::T3->getKey($orep, $comp); 
        $nserial = NWS::T3->getKey($rep, $comp);  

        #if (!$nserial && defined($nserial)) {# move the key from old to new
        #   NWS::T3->copyKey($comp, $orep, $rep);
        #   $nserial = NWS::T3->getKey($rep, $comp);  
        #}

        if ($oserial eq $nserial) {
           $hm->stateEvent($comp, $report, $rep, $orep, 'CIM_PhysicalPackage', $nserial, $wwn);
           foreach my $el ('Port1State','Port2State') {
             $hm->alarm($report, $orep, "T3", $comp, "fruDisk$el", $shortid, $id, $wwn);
           }
           if ($rep->{"$comp.pathstat"}) {
             $hm->alarm($report, $orep, "T3", $comp, "pathstat", $shortid, $id, $wwn);
           }

        } else {
           if ($oserial) {
             $hm->removeCompEvent($comp,$physicalFrame,$report,'CIM_PhysicalPackage',$oserial, $wwn);
           }
           if ($nserial) {
             my($part) = NWS::T3->newDiskDrive($rep, $comp);
             $hm->insertCompEvent($comp,$physicalFrame, $report, $part, $nserial, $wwn);
             $invalidate_catalog = 1;
           }
        }
     }

# Volumes (3)
     for ($y=1; $y <= 3; $y++) {
        $comp = "volume.u${x}vol$y";
        my($ostatus) = $orep->{"$comp.volStatus"};
        my($nstatus) = $rep->{"$comp.volStatus"};
        if ($ostatus && $ostatus ne $nstatus) {
           #   my($volkey) = CIM::Key->new( ["NWS_StorageVolume",
           #       SystemName        => "Volume",
           #       CreationClassName => 'NWS_StorageVolume',
           #      DeviceID    => "$wwn.u${x}vol$y"] );

           $hm->stateEvent($comp, $report, $rep, $orep, 
                           'CIM_PhysicalPackage', "$wwn.u${x}vol$y",  $wwn);
        }
     }
  }
#<Volume Slicing and Masking>
  if(($rep->{"sys.sysVolSliceIsEnabled"} || $orep->{"sys.sysVolSliceIsEnabled"})&&
     ($rep->{"sys.sysVolSliceIsEnabled"} eq "yes"  ||
      $orep->{"sys.sysVolSliceIsEnabled"} eq "yes")) {
    #<volume slicing enabled>
    $comp = "sys.sysVolSliceIsEnabled";
    my($ostatus) = $orep->{$comp};
    my($nstatus) = $rep->{$comp};
    if ($ostatus ne $nstatus && $nstatus eq "yes" && $ostatus && $nstatus) {
        $hm->alarmEvent("", $report, $wwn, "Volume Slicing is now on!"  , 0, "sysvolslice");
    } elsif ($ostatus ne $nstatus && $ostatus eq "yes" && $nstatus && $ostatus) {
      # Add Event to say volslicing is off
        $hm->alarmEvent("", $report, $wwn, "Volume Slicing is now off!"  , 1, "sysvolslice");
    }
    #</volume slicing enabled>
  
    #<lun count> 
    $comp = "lun.count";
    my ($ocount) = $orep->{$comp};
    my ($ncount) = $rep->{$comp};
    if ($ocount < $ncount && $ncount && $ocount) {
    $hm->alarmEvent("", $report, $wwn, "LUN(s) have been added."  , 0, "sysvolslice");
    } elsif ($ocount > $ncount && $ncount && $ocount) {
      # Add Event to say luns have been removed
    $hm->alarmEvent("", $report, $wwn, "LUN(s) have been removed."  , 1, "sysvolslice");
    }
    #</lun count> 
  
    #<lun permision changes>
    for($y = 1; $y <= 16; $y++) {
      #<lun default permision changes>
      my $lun = "lun.".$y;
      my $comp = $lun.".lunMaskAccessDefault";
      if($orep->{$comp} ne $rep->{$comp} && $orep->{$comp} && $rep->{$comp}){
        $hm->alarmEvent("", $report, $wwn, 
          "LUN $comp default permission have been changed from".
  		  " $orep->{$comp} to $rep->{$comp}.",
           0, "sysvolslice");
      }
      #</lun default permision changes>
    }
  
    #<lun masking permision changes>
    my @old_initiators=(grep {/lun.\d+.Initiator.\d+.lunMaskWWN/} (keys %$orep));
    my @new_initiators=(grep {/lun.\d+.Initiator.\d+.lunMaskWWN/} (keys %$rep));
    #find Initiators that were in old but not new
    my @changed_initiators=undef;
    my @union_initiators=undef;
    my %count;
    foreach my $e (@old_initiators, @new_initiators) {$count{$e}++;}
    foreach my $e (keys %count){
      if ($count{$e} == 1) {
        print "pushing $e\n diff";
        push @changed_initiators, $e;
      } elsif ($count{$e} == 2) {
        push @union_initiators, $e;
      }
    }
  
    foreach my $initiator (@union_initiators){
      if ($orep->{$initiator} ne $rep->{$initiator}){
      $hm->alarmEvent("", $report, $wwn, 
          "$initiator changed from $orep->{$initiator} to $rep->{$initiator}" , 1, "sysvolslice");
      }
    }
    foreach my $initiator (@changed_initiators){
      if ($orep->{$initiator}){
        #Remove Event Initiator
        $hm->alarmEvent("", $report, $wwn, "$initiator=$orep->{$initiator} was removed" , 1, "sysvolslice");
      } elsif ($rep->{$initiator}){
        $hm->alarmEvent("", $report, $wwn, "$initiator=$rep->{$initiator} was added" , 1, "sysvolslice");
      }
    }
    foreach my $initiator (@old_initiators){
      ($comp, my $junk) = split(/lun.\d+.Initiator.\d+/, $initiator);
      my $old_access = $orep->{$comp.".lunMaskAccess"}; 
      my $new_access = $rep->{$initiator.".lunMaskAccess"};
  
      if ($old_access ne $new_access){
      $hm->alarmEvent("", $report, $wwn, 
          "The access permission has changed for LUN $comp from ".
  				"$old_access to $new_access.", 
           1, "sysvolslice");
      }
    }
    #</lun masking permision changes>
    #</lun permision changes>
  }
#</Volume Slicing and Masking>
}

  
sub status {
   my($hm, $rep, $orep, $comp) = @_;
   my($pdm) = $hm->{pdm};
   my($map) = $pdm->getDeviceStateMap("t3.availability");

   if ($comp =~ /volume/) {
     my($status) = $rep->getState("$comp.volStatus");
     my($ostatus) = $orep->getState("$comp.volStatus");
     my($old) = $map->get("volStatus.$ostatus");
     my($new) = $map->get("volStatus.$status");
     return ("$ostatus", "$status", $old, $new);
   }
      
   my($state) = $rep->getState("$comp.fruState");
   my($ostate) = $orep->getState("$comp.fruState");
   my($status) = $rep->getState("$comp.fruStatus");
   my($ostatus) = $orep->getState("$comp.fruStatus");

   my($old) = $map->get("fruStatus.$ostatus") . $map->get("fruState.$ostate");
   my($new) = $map->get("fruStatus.$status") . $map->get("fruState.$state");

   $old = ($old eq "11")? 1:0;
   $new = ($new eq "11")? 1:0;
   return ("$ostatus-$ostate", "$status-$state", $old, $new);
}

# static method
# return status-state and 0/1
#  =controller.u1ctr
#  =power.u1pcu1
#  =power.u1pcu2
#  =loopcard.u1l1
#  =loopcard.u1l2
#  =disk.u1d1
#  =disk.u1d2
#  =disk.u1d3
#  =disk.u1d4
#  =disk.u1d5
#  =disk.u1d6
#  =disk.u1d7
#  =disk.u1d8
#  =disk.u1d9


sub compStatus {
   my($hm, $rep, $comp) = @_;

   my($map) = PDM->getDeviceStateMap("t3.availability");

   my($state) = $rep->get("$comp.fruState");
   my($status) = $rep->get("$comp.fruStatus");

   my($new) = $map->get("fruStatus.$status") . $map->get("fruState.$state");

   $new = ($new eq "11")? 1:0;
   return ("$status-$state", $new);
}





sub NUhealth1 {
  my($report, $pdm, $cat, $comp0, $rep, $orep, $cim1, $physicalFrame, $type, $wwn) = @_;
  my($sd, $pertains, $ed , $ev, $key, $contain);

   my($comp) = "$cat.$comp0";
   my($oserial) = $orep->get("$comp.fruSerialNo") ;
   my($nserial) = $rep->get("$comp.fruSerialNo") ;

   if ($oserial eq $nserial) {
      my($map) = $pdm->getDeviceStateMap("t3.availability");

      my($state) = $rep->get("$comp.fruState");
      my($ostate) = $orep->get("$comp.fruState");
      my($status) = $rep->get("$comp.fruStatus");
      my($ostatus) = $orep->get("$comp.fruStatus");

      my($old) = $map->{"fruStatus.$ostatus"} . $map->{"fruState.$ostate"};
      my($new) = $map->{"fruStatus.$status"} . $map->{"fruState.$state"};

      $old = ($old eq "11")? 1:0;
      $new = ($new eq "11")? 1:0;

      if ($old != $new) { # availability change.
         my($data) = "State=[o:$ostate,n:$state],Status=[o:$ostatus,n:$status]";

         $ev = CIM::Instance->new('NWS_StateChangeEvent', [
             [ EventType    => 't3.StateChangeEvent'   ],
             [ EventId      => $pdm->getEventSequence  ],
             [ CurrentState => $new],
             [ PriorState   => $old],
             [ Data         => $data],
                    ]);

         $sd = Events->sourceDetector({ event => $ev });

         $key = CIM::Key->new( [$cim1,   
                  Tag               => $nserial,
                  CreationClassName => $cim1]);

         $pertains = CIM::Instance->new('NWS_EventPertainsToPhysicalElement', [
             [ Event       => $ev  ],
             [ Element     => $key ],
               ]);

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

         $pdm->saveMessage($ed);
      }
   } else {  # new component
      if ($oserial) {  # remove old one
         $ev = CIM::Instance->new('NWS_Event', [
             [ EventType   => 't3.TopologyEvent'  ],
             [ Description => "$cat-remove" ],
             [ EventId     => $pdm->getEventSequence  ]]);

         $sd = Events->sourceDetector({ event => $ev });
         
         $key = CIM::Key->new( [$cim1,   # key of the disk
                  Tag               => $oserial,
                  CreationClassName => $cim1]);

         $contain = CIM::Instance->new( 'CIM_Container', [
                  [GroupComponent => $physicalFrame], # frame is a package
                  [PartComponent  => $key],           # package is an element
                  [LocationWithinContainer => $rep->get("$comp.fruId")],
                   ]);

         $pertains = CIM::Instance->new('NWS_EventPertainsToContainer', [
                  [Event          => $ev   ],
                  [Association    => $contain ],
                  [DiscoveryType => "D"   ],   # delete
               ]);

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

         $pdm->saveMessage($ed);
      } 
      if ($nserial) {   # add new disk
         $ev = CIM::Instance->new('NWS_Event', [
             [ EventType   => 't3.TopologyEvent'  ],
             [ Description => "$cat-add" ],
             [ EventId     => $pdm->getEventSequence  ]]);

         $sd = Events->sourceDetector({ event => $ev });
         my($part);
         if ($type eq "D") {
           $part = NWS::T300->newDiskDrive($rep, $comp0);
         } elsif ($type eq "C") {
           $part = NWS::T300->newController($rep, $comp0);
         } elsif ($type eq "L") {
           $part = NWS::T300->newLoopCard($rep, $comp0);
         } elsif ($type eq "P") {
           $part = NWS::T300->newPowerUnit($rep, $comp0);
         }
         $pertains = CIM::Instance->new('NWS_EventPertainsToPhysicalElement', [
             [ Event       => $ev  ],
             [ Element     => $part->[1]],
               ]);

         $contain = CIM::Instance->new('CIM_Container', [
              [GroupComponent           => $physicalFrame],
              [PartComponent            => $part->[1]],
              [LocationWithinContainer  => $rep->get("$comp.fruId")], 
               ]);
         
         $ed = Message->new( { id        => $report->id,
                       instances => [$ev, @$sd, @$part, $pertains , $contain],
                       severity  => Message::SEVERITY_ERROR });

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


1;
