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

#  $Name: bld61_002 $ 
#  $Id: SunMC.pm,v 1.4 2005/06/22 20:02:29 edunning Exp $

use PDM;
use Carp;
use Message;
use SAF;
use Util;
use strict;
use Catalog;
use Util::Http;

use base 'Provider';
sub revision {'$Revision: 1.4 $'}

sub description {"SunMC"}
sub id          {"sunmc"}
sub url         {":18055"}
sub saf         {0}

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

  my($p) = { pdm => $pdm };

  bless($p,'Provider::SunMC');
  return $p;
}

#SAN-T3
#SAN-Switch
#SAN-VE                 (instead of Vicom)
#SAN-Storage
#SAN-SE-Series


sub UPDATE {
  my($class, $q) = @_;
  my($active, $ip, $proxy, $to, $err, $name, $nat, $info, $ip2);
  my($renv, $dev, $host,$notifs, $o);
   my $deny = Roles->verifyRole($q, "admin");
  my $G = Labels->read();
  my $L = Labels->read('Provider')->section('sunmc');

  if ($q->{ACTION_update}) {
    ($renv, $dev, $host,$notifs) = PDM::ConfigFile->read;
    unlink System->get_home() . "/DATA/last_sunmc_topo";
    $renv->{'pro.sunmc.active'} = $q->{active}? "Y":"N";
    $renv->{'pro.sunmc.ip'}     = $q->{ip};
    $renv->{'pro.sunmc.frequency'}     = ($q->{freq} +0) || 6;
    PDM::ConfigFile->write( $renv, $dev, $host,$notifs);

    $err = Html->info($L->{err_1}); 
  }

  ($renv, $dev, $host,$notifs) = PDM::ConfigFile->read;

  if ($renv->{'pro.sunmc.active'} eq "Y") {
    $active = "checked" ;
  } else {
    $info = "<font color=red><b>$G->{inactive}</b>";
  }

  $ip      = $renv->{'pro.sunmc.ip'};
  $nat     = $renv->{'pro.sunmc.nat'};
  my $freq = $renv->{'pro.sunmc.frequency'};
  $ip      = Util->name2ip() if (!$ip);

   my $scr = Html::Screen->new();
  $scr->add(" $err <form  method=get> <input type=hidden name=GO value=GUI::Providers::display>
          <input type=hidden name=option value=$q->{option}>");

  $scr->table({ title => $L->{label}, labelWidth => "40%"},
      [
       [f => $G->{active}, "<input type=checkbox name=active $active> $info"],
       [f => $G->{ip},     "<input type=text name=ip value=\"$ip\" size=40>" ],
       [f => $L->{heartbeat}, "<input type=text name=freq value=\"$freq\" size=2 maxlength=2>" ],
      ]);

  if (!$deny) {
     $scr->button2( [
      [ l => 'ACTION_update',  $G->{submit_update} ],
      ]);
  }
  $scr->add("</form>");
  return $scr->out();
}


sub RUN {
  my($pro, $idList) = @_;
  my($notif, $p, $ed, $id, $cat, %SP, %MAP);
  my($ed_desc, $email_text);
  my $edocs     = PDM->getMessagesFromList($idList);
  $DB::single = 1;
  my $ID = $pro->id();

  my($renv, $devices, $hosts, $notifs) = PDM::ConfigFile->read();

  if ($renv->{"pro.$ID.active"}  ne "Y") {
     Debug->print2("  not active, skipping.");
     return;
  }

  my $SEQ  = PDM->getCacheHandle($ID . "_seq");
  my $time = System->srs_time();
  my $ip   = Util->name2ip($renv->{hostname});
  my $freq = $renv->{"pro.$ID.frequency"} || 6;
  my $dtd = "http://localhost/srs_station_message.dtd";

  my $HEAD =<<EOF;
<?xml version="1.0" encoding="US-ASCII" standalone="no"?>
<!DOCTYPE srs_station_message SYSTEM "$dtd">
EOF

  my($saf) = SAF->new({ file => $ID, size => 2000000 } );
  my($saferr, $safcnt, $old);
  while ( ($old = $saf->read()) ) {
     my $err = $pro->send($renv, $old);
     if ($err) {
       $saf->failed($old);
       $saferr++;
     } else { 
       $safcnt++;
     }
  }
  if ($saferr) {
    Debug->err(SRS => "Could not send $saferr old messages!");
  } elsif ($safcnt ) {
    Debug->print2("  - SRSProvider: $safcnt old messages sent!");
  }
  $saf->done;
  $saferr = 0;

  my($last_topo, $mess);
  my $topo = $pro->srs_topo($devices, $hosts, $renv, \%MAP);
  my $LD =  System->get_home(). "/DATA/last_${ID}_topo";

  if (open(O, $LD)) {
     my @a = <O>; close(O);
     $last_topo = join("", @a);
  }

  if (PDM->getEventCount == 0 && $topo eq $last_topo) {
    if (Timer->getTimer(uc($ID)) > $freq * 60) {
      Timer->resetTimer(uc($ID));
      $SEQ->{seq}++;
      my $frq = $freq * 60;
      my $srs =<<EOF;
$HEAD
 <srs_station_message seq_no="$SEQ->{seq}" timestamp="$time" 
                      sourceIP="$ip" sourceName="RASAGENT">
    <heartbeat period="$frq" />
 </srs_station_message>
EOF
      my $err = $pro->send($renv, $srs);
      if ($err) {
        Debug->err(SRS => "Cannot send:$err");
        $saf->write($srs) if ($pro->saf());
      } 
      Debug->print2("  - SRSProvider: HeartBeat");
    }
    return;
  }
  Timer->resetTimer(uc($ID));

  my $transmission = 0;

  if ($topo ne $last_topo) {
     $SEQ->{seq}++;
     $transmission = 1;
     $mess =<<EOF;
$HEAD
<srs_station_message seq_no="$SEQ->{seq}" timestamp="$time" 
                      sourceIP="$ip" sourceName="RASAGENT">
   $topo
</srs_station_message>
EOF
     my $err = $pro->send($renv, $mess);
     Debug->print2("  - ${ID}Provider: topology");
     if ($err) {
        Debug->err(SRS => "Cannot send:$err");
        $saf->write($mess) if ($pro->saf());
     } else {
       open(O, ">$LD");
       print O $topo;
       close(O);
     }
  }
  
  my($ev, $x, $alert, $severity, $al, $agent, $host, $desc);
  my($event_desc, $event_type, $source);
  my($event_id, $event_time);
  $DB::single = 1;
  my($srs) ;

  for ($x=0; $x <= $#$edocs; $x++) {
     $ed   = $edocs->[$x];
     next if ($ed->type() eq Message::TYPE_ALERT); # Skip alerts
     next if ($ed->id("active") eq "N");

     $ev       = $ed->instances(0);
     $event_type = $ev->value("EventType");
     my $caption = $ev->value("Caption");
     my $g_no    = $ev->value("GridNo");
     
#           RAS    SRS
#  warning  1      3
#  error    2      4/minor 5/major
#  down     3      5/major 6/critital
#
     my $reporting_level      = $renv->{'pro.sunmc.reporting_level'}||0;
     Debug->print3("SUNMC Reporting Level is $reporting_level\n");

     my $actionable = $ev->propertyByName("Actionable")->value();
     next if ($ev->value("MgmtLevel") eq "DS");
     $severity   = $ev->propertyByName("Severity")->value();
     $severity = int($severity+ 0.5);

     next if ($severity < $reporting_level && $actionable ne "True");

     $severity += ($severity < 2) ? 2 : 4 ;

     $event_desc = $ev->value("Description");
     $event_desc .= " " . $ev->value("Disclaimer");
     my $event_desc0 = $event_desc;
     $event_desc .= " [EventCode: 1.$g_no] " if ($g_no);

     my $data;
     if (substr($event_desc,-1) eq ":") {
       if ($data) {
         my @X = split(/\n/, $data);
         $event_desc .= " ($#X lines)";
       }
     }
     $event_desc = Util->escapeValue($event_desc);
     
     $event_id   = $ev->propertyByName("EventId")->value();
     $event_time = $ev->propertyByName("EventTime")->value();
     $event_time = substr($event_time,0,8) . "." .  substr($event_time,8,6) . 
                   substr($event_time, -5,3);
     $agent      = $ed->instances(1);
     $host       = $ed->instances(4);
     # $source     = $ev->propertyByName("SourceIP")->value();
     $cat   = $ed->id("category"); #  or System->model();
     next if (index("stools4,topo,mpxio,san", $cat) >= 0);

     my $target  = $ev->value("Target");
     $target =~ s/[\:\.]/-/g;
     $source     = $MAP{$target}[0];
     my $module  = $MAP{$target}[1];
     if (!$source) {
        Debug->print3("${ID}Provider: Cannot find source_ip for $target, defaulting to master_ip");
        $source = Util->name2ip($renv->{hostname});
        $module = "rasagent";
     }
        
     my($sys)  = $ed->instances(4);
     $sys = $ed->instances(8) if ($sys->type() eq "H");
     $transmission = 1;

     $SEQ->{seq}++;
     $srs =<<EOF;
$HEAD
 <srs_station_message seq_no="$SEQ->{seq}" timestamp="$time" 
                      sourceIP="$ip" sourceName="RASAGENT">
    <alarm source="$source" provider="RASAGENT" module="$module"
           alarm_id="$event_id" timestamp="$time" state="O" severity="$severity"
           type="$event_type">
          $event_desc
    </alarm>
 </srs_station_message>
EOF
     my $err = $pro->send($renv, $srs);
     if ($err) {
       Debug->err(SRS => "${ID}Provider: Cannot send message :$err");
       $saf->write($srs) if ($pro->saf());
       $saferr++;
     } else { 
       Debug->print2("  - ${ID}Provider: alarm $event_desc0 ");
     }
  }
#


}

sub send {
   my($pro, $renv, $mess) = @_;
   my($D);
   my $ID = $pro->id();
   my $ext = $pro->url();

   foreach my $srs_ip ('ip') {
     my($url) = $renv->{"pro.$ID." . $srs_ip};
     next if (!$url);

     $url = "http://$url" if (substr($url,0,4) ne "http");
     $url .= $ext;

     my($err, $value) = Util::Http->post($url, $mess, 20);

     if ($pro->id() ne "sunmc") {    # deal with error unless it's sunmc
       if ($err =~ /500/) {  # retry
          sleep(1);
          ($err, $value) = Util::Http->post($url, $mess, 20);
       }
       if ($err) {
          $err .= ": $value";
          return $err;
       }
     }
   }
   return undef;
}


sub srs_topo {
  my($pro, $devices, $hosts, $renv, $MAP) = @_;
  my(%H,%G, $port, %IP);
  my($acronym) = $renv->{GSV_ACRONYM};
  my %TYPE;
  $TYPE{""}                = $renv->{solution_model};
  $TYPE{$renv->{hostname}} = $renv->{solution_model};
  my $SUNMC = $pro->id() eq "sunmc";

  foreach my $h (@$hosts) {
     $TYPE{$h->{hostname}} = $h->{solution_model};
     $IP{$h->{hostname}} = $h->{ipno};
  }

  foreach my $d (@$devices) {
     my $ho = $d->{host} || $renv->{hostname};

     if (index("3510,6020,6120,t3",$d->{type}) >= 0 && $d->{mgmtLevel} ne "C") { # C= not a rack component
         my $wwn        = $d->{key};
         my $wwn0       = $wwn;
         my $tt         = $d->{type};
         my $group_type = $d->{type};
         $wwn           =~ s/\./-/g;
         $MAP->{"$tt-$wwn"}[0] = $d->{ipno};
         if ($SUNMC) {
           $MAP->{"$tt-$wwn"}[1] = "$tt-$d->{name}";
           $wwn = $d->{name};
         } else {
           $MAP->{"$tt-$wwn"}[1] = $d->{name}; # "rasagent";
           $wwn = $d->{name} . "-$wwn";
         }

         if ($wwn )  {
            $group_type = "6120" if ($tt ne "t3");
            $G{$group_type} .=<<EOF;
      <node action="ADD" address="$d->{ipno}" name="$tt-$wwn" model="$tt" serial="$wwn0"/>
EOF
         }
     } elsif ($d->{type} =~ /^se\d*$/ && $d->{mgmtLevel} eq "D") { # rack as devices

         my $wwn  = $d->{key};
         my $wwn0 = $wwn;
         my $tt = $d->{type};
         $wwn =~ s/\./-/g;
         $MAP->{"$tt-$wwn"}[0] = $d->{ipno};
         if ($SUNMC) {
           $MAP->{"$tt-$wwn"}[1] = "$tt-$d->{name}";
           $wwn = $d->{name};
         } else {
           $MAP->{"$tt-$wwn"}[1] = $d->{name}; # "rasagent";
           $wwn = $d->{name} . "-$wwn";
         }

         if ($wwn )  {
            $G{se} .=<<EOF;
      <node action="ADD" address="$d->{ipno}" name="$tt-$wwn" model="$tt" serial="$wwn0"/>
EOF
         }

     } elsif ($d->{class} =~ /^switch/ && $d->{mgmtLevel} ne "C") {
         my $t    = $d->{type};
         my $wwn  = $d->{wwn};
         my $wwn0 = $wwn;
         $wwn =~ s/\./-/g;
         $MAP->{$t . "-$wwn"}[0] = $d->{ipno};
         if ($SUNMC) {
           $MAP->{"$t-$wwn"}[1] = "$t-$d->{name}";
           $wwn = $d->{name};
         } else {
           $MAP->{$t . "-$wwn"}[1] = $d->{name}; # "rasagent";
           $wwn = $d->{name} . "-$d->{wwn}";
         }

         if ($wwn) {
            $G{switch} .=<<EOF;
      <node action="ADD" address="$d->{ipno}" name="$t-$wwn" model="$t" serial="$wwn0"/>
EOF
         }

     } else {
         my $host = $d->{host} || $renv->{hostname};
         &addModule(\%G, $host, $d->{type}, $d->{key}, $MAP, $d->{name}, $TYPE{$d->{host}}, $IP{$d->{host}});
     }
  }
  &addModule(\%G, $renv->{hostname}, "message", System->hostid(), $MAP);
  &addModule(\%G, $renv->{hostname}, "host", $renv->{hostname}, $MAP);

  foreach my $h (@$hosts) {
     &addModule(\%G, $h->{hostname}, "message", $h->{hostid}, $MAP, undef, undef, $h->{ipno});
     &addModule(\%G, $h->{hostname}, "host", $h->{hostname}, $MAP, undef, undef, $h->{ipno});
  } 
    
# the SRS provider name MUST remain RASAGENT 
# the version 2.2 maps to StorADE 2.0
# Changes to this require contact with the SRS team, Phil Cornelius

  my $out =<<EOF;
<topology type="FULL">
  <provider name="RASAGENT" vendor="SUN Microsystems" version="2.2" 
            description="$acronym Agent"/>
EOF
  my %N = (6020 => "SAN_Storage", 6120   => "SAN_Storage", 
           t3   => "SAN_T3",      switch => "SAN_Switch", se => "SAN_SE_Series");
  my $out2;

  foreach my $x (keys %G) {
     if ((index("6020,6120,t3", $x) >= 0) || substr($x,0,6) eq "switch" || $x =~ /^se\d*$/ ) {
        $out .= "    <group name=\"$N{$x}\" type=\"$x\">\n$G{$x}\n    </group>\n";
     } else {
        $out2 .= "$G{$x}      </node>\n";
     }        
  }
  $out .= $out2;
  $out .= "</topology>\n";
  return $out;
}

sub addModule {
  my($G, $host, $type, $wwn, $MAP, $dev_name, $id, $ipno) = @_;
  my($d_ip, $d_host);
  $d_host = $host || System->hostname();
  $d_ip = $ipno || Util->name2ip($d_host);
  $wwn =~ s/\./-/g;
  $MAP->{"$type-$wwn"}[0] = $d_ip;
  $id .= "-" if ($id);

  if (!$G->{$d_host}) {

      $G->{$d_host} .=<<EOF;
      <node action="ADD" address="$d_ip" name="$d_host" model="rashost" serial="$id$d_ip">
EOF
   }
   my $name= "$type-";
   $name .= "$dev_name-" if ($dev_name);
   $name .= $wwn;
   $MAP->{"$type-$wwn"}[1] = $name;
   $G->{$d_host} .=<<EOF;
        <module name="$name" vendor="SUN" model="$type" 
                   serial="$wwn" version="1.0" description="$type">
        </module>
EOF
}

  
1;
