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

#  $Id: SWITCH2.pm,v 1.23 2002/10/27 21:43:19 ccadieux Exp $

use strict;
use Agent;
use base 'Agent';
use Net::Telnet;
use Agent::SWITCH;
use Util;

sub isSelectable {"Sun 2GB Switch"}

sub revision {'$Revision: 1.23 $'}
sub new {
  my($self) = Agent->new();

  bless ($self, 'Agent::SWITCH2');
  return $self;
}
use vars qw($ERR);

  
sub RUN {
  my($agent,$ras_flag) = @_;
  my(%DONE, $HBA, $logfile, $r, @results);
  my( @all_connect_errors);
  my( @lux_dif, $dif, $xml, @all_dif);
  my($ev, @stats, $id, $log_lines, $sdt, $pdm);
  $pdm = $agent->{pdm};
  my($renv) = System->get_renv();

  $DB::single=1;
  Timelapse->start(ref($agent));

  my($today) = Util->today("YMDH");
  my($dc) = 0;

  foreach my $device ( $agent->deviceList()) {
     if($device->{active} eq "N"){
	Debug->print2("-> Switch2: skipping device $device->{name}: $device->{ip} - Monitoring is not turned on for this specific device.");
	next;
     }

    $dc++;
    Debug->print1("-> Switch2: reading device $device->{name}: $device->{ip}");

    if (!$device->{ip}) {
        Debug->err( 'IP_NOT_FOUND',"Switch at $device->{name}" );
        next;
    }

    my($connect_errs, $wwn, $report) = $agent->INSTRUMENTATION($device);

    $wwn = lc($wwn);
    if ($wwn && $wwn ne $device->{wwn}) {
       Debug->errNoRepeat(SWITCH_NEWIP => $device->{ipno}, 24, "wwn of $device->{ipno} changed from $device->{wwn} to $wwn");
    }

    $id = {   accessName  => $device->{name},
              deviceName  => $device->{wwn},
              active      => $device->{active},
              display     => "$device->{name} (ip=$device->{ip})",
              class       => $device->{class},
              name        => $device->{name},
              category    => Report::CAT_SWITCH2,
              ip          => $device->{ip},
           };

    $report = {} if (!$report);
    $agent->copyDev($device, $report);

    $device->{ipno} = Util->name2ip($device->{ip});
    $report->{"id.name"} = $device->{name};
    $report->{"id.ip"}   = $device->{ip};
    $report->{"id.ipno"} = $device->{ipno};

    if ($connect_errs || !$wwn) {
        $report->{'id.connect_errs'} = $connect_errs;
        $pdm->saveReport(
          Report->new($id, $report , [], Report::STATUS_CANNOT_CONNECT));

    } else {
        $pdm->saveReport(Report->new($id, $report , $log_lines));
    }
  }
  Debug->print2("  No devices found") if (!$dc);

  Timelapse->stop(ref($agent));
}

sub getDevStatus {
  my($class, $dev) = @_;
  my %R;

  $ERR = $class->getLinks($dev, \%R);
  $ERR = $class->getPortStatus($dev, \%R);
  return ($ERR, \%R);
}


sub getLinks {
  my($class, $dev, $R) = @_;
  my($x, $err, $ports, $rem);
  my $DIR  = System->get_home() . "/snmp/bin";
  my($renv) = System->get_renv();
  my($TO) = $renv->{'timeout.snmp'} || 10;
  my $wwn = $dev->{wwn};
  my $mibwwn = Util->wwn2mib($wwn);
 
  my$MIBS = System->get_home() . "/snmp/mibs";
  my $OPT = "-t $TO -r 0 -m all -Osb ";
  ($err,$ports) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} public connUnitNumports", 
                 "sanbox_version.txt", $TO+5);

  foreach my $l (@$ports) {
      if ($l =~ /$mibwwn/) {
         my(@a) = split(/ +\= */, $l);
         $R->{"port.count"} = $a[1];
         last;
      }
  }

  ($err,$rem) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} public connUnitLinkPortWwnX.$mibwwn", 
                 "sanbox_version.txt", $TO+5);
  my @PORTS;
  my $cnt = 1;
  foreach my $l (@$rem) {
     $l =~ /=\s+Hex: (.*)/;
     my $x = lc($1);
     $x =~ s/ //g;
     if ($l =~ /$mibwwn/) {
         $PORTS[$cnt] = hex substr($x,2,2);
     }
     $cnt++;
  }

  ($err,$rem) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} public connUnitLinkPortWwnY.$mibwwn", 
                 "sanbox_version.txt", $TO+5);
  $cnt = 1;
  foreach my $l (@$rem) {
     $l =~ /=\s+Hex: (.*)/;
     my $x = lc($1);
     $x =~ s/ //g;
     if ( defined($PORTS[$cnt]) ) {
        $R->{"port." . $PORTS[$cnt] . ".link_wwn"} = substr($x,0,16);
        #$R->{"port." . $PORTS[$cnt] . ".link_port"} = hex substr($x,2,2);
     }
     $cnt++;
  }
}

sub getPortStatus {
  my($class, $dev, $R) = @_;
  my($x);
  my $DIR   = System->get_home() . "/snmp/bin";
  my($renv) = System->get_renv();
  my($TO)   = $renv->{'timeout.snmp'} || 10;
  my $wwn   = $dev->{wwn};
  my $mibwwn = Util->wwn2mib($wwn);
 
  my $MIBS = System->get_home() . "/snmp/mibs";
  my $OPT = "-t $TO -r 0 -m all -Osb ";

  # Get port type
  my $passwd;
  if($dev->{telnet}){
    $passwd = Util->decode($dev->{telnet});
  }

  my $SDIR = System->get_home() . "/sbin" ;
  my($err,$rem) = Util->run_command(
               "$SDIR/qlogicSwitchPortType $dev->{ipno} $passwd", 
               "sanbox_version.txt", $TO+5);


  foreach my $l (@$rem) {
     if($l =~ /ERROR/){
        $R->{"port.0.type"} = "ERROR: ENSURE PASSWORD HAS BEEN ENTERED FOR THIS DEVICE";
        Util->dump($R, "/debug/Ra");
     }elsif($l =~ /Port /){
        my($f1, $f2) = split(/ = /, $l);
        my ($nport, $port, $ntype) = split(/ /, $f1);
        $R->{"port.$port.type"} = $f2;
     }
  }

  # get port state
  my($err,$rem) = Util->run_command(
               "$DIR/snmpwalk $OPT $dev->{ipno} public connUnitPortState.$mibwwn", 
               "sanbox_version.txt", $TO+5);

  foreach my $l (@$rem) {
    if ($l =~ /$mibwwn/) {
      my($f1, $f2) = split(/ = /, $l);
      my $ix = rindex($f1, ".");
      my $port = substr($f1,$ix+1) - 1;
      $ix = index($f2,"(");
      my $type = substr($f2,0,$ix);
      $R->{"port.$port.state"} = $type;
    }
  }
  my($err,$rem) = Util->run_command(
               "$DIR/snmpwalk $OPT $dev->{ipno} public connUnitPortSpeed.$mibwwn", 
               "sanbox_version.txt", $TO+5);

  my $port_speed;
  foreach my $l (@$rem) {
    if ($l =~ /$mibwwn/) {
      
      my($f1, $f2) = split(/ = /, $l);
      my $ix = rindex($f1, ".");
      my $port = substr($f1,$ix+1) - 1;
      if(($f2 =~ /10625/) || ($f2 =~ /102400/))
      {
         $port_speed = "1Gb";
      }
      else
      {
         $port_speed = "2Gb";
      }
      $R->{"port.$port.speed"} = $port_speed;
    }
  }
  
}


#
# no FC stats yet
#
sub getStats {
  my($class, $device) = @_;

}


# returns 
#  $V->{ASIC} = "06"
#  $V->{PCB}  = "14"
#  $V->{PROM} = "4.05.00"
#  $V->{FLASH} = "048.71.3D";
sub getVersion {
  my($agent, $device) = @_;

  my $DIR = System->get_home() . "/snmp/bin";
  my $renv = System->get_renv();
  my $TO = $renv->{'timeout.snmp'} || 10;
  my $ip = $device->{ip};
  my $wwn = $device->{wwn};
  my $mibwwn = Util->wwn2mib($wwn);

  my($MIBS) = System->get_home() . "/snmp/mibs";
  $ENV{LD_LIBRARY_PATH} = System->get_home() . "/snmp/lib";
  my($OPT) = "-r 0 -t $TO -m all -Obs ";

  my($err0,$version) = Util->run_command("$DIR/snmpwalk $OPT $ip public connUnitRevsRevId.$mibwwn", 
                      "sanbox_version.txt", $TO + 5);
  my %V;

  if ($err0) {
     $ERR = $err0;
     return undef;
  } 
     my (@Val);
     foreach my $l (@$version) {
        next if ($l !~ /$mibwwn/);
        if ($l =~ /RevsRevId/) {
           $l =~ /\.(\d+) = (.*)/;
           my $port = $1;
           my $name = $2;
           $name =~ s/"//g;
           my $ix = index($name, " Hex:");
           $name = substr($name, 0, $ix) if ($ix > 0);
           $Val[$port] = $name;
        } 
     }

  my($err0,$version) = Util->run_command("$DIR/snmpwalk $OPT $ip public connUnitRevsDescription.$mibwwn", 
                      "sanbox_version.txt", $TO + 5);
  if ($err0) {
     $ERR = $err0;
     return undef;
  } 
  my (@N);
  foreach my $l (@$version) {
     next if ($l !~ /$mibwwn/);
     if ($l =~ /RevsDescription/) {
        $l =~ /\.(\d+) = (.*)/;
        my $port = $1;
        my $name = $2;
        $name =~ s/"//g;
        $name =~ s/ /_/g;
        $N[$port] = $name;
     }
  }
  my $x;
  for ($x=1; $x <= $#N; $x++) {
     $V{$N[$x]} = $Val[$x];
  }
  return \%V;

}




sub INSTRUMENTATION {
  my($agent, $device) = @_;
  my(@s, %dev, $in, %info);
  my($connect_err, %C, $err0, $system, $sensors);
  my($port,  $config, $err4);
  my(%R);
  my($ip)    = $device->{ip};
  my(@counts, @stats, $stat, $x);
  my($DIR)   = System->get_home() . "/snmp/bin";
  my($renv)  = System->get_renv();
  my($TO)    = $renv->{'timeout.snmp'};
  my $wwn    = $device->{wwn};
  my $mibwwn = Util->wwn2mib($wwn);

  my($MIBS)  = System->get_home() . "/snmp/mibs";
  $ENV{LD_LIBRARY_PATH} = System->get_home() . "/snmp/lib";
  my($OPT)   = "-r 0 -t $TO -m all -Osb ";

  my ($stderr);
  ($err0,$system, $stderr) = Util->run_command("$DIR/snmpwalk $OPT $ip public system", 
                      "sanbox_version.txt", $TO+5);

  if($stderr =~ /Timeout/)
  {
     return ($stderr, undef,undef);
  }

  if ($err0) {
     return ($err0, undef,undef);

  } elsif ("@$system" =~ /Timeout:/) {
     return ("@$system", undef,undef);
  }


  foreach my $x (@$system) {
     my(@a) = split(/ +\= */, $x);
     $a[1] = substr($a[1],1,-1) if (substr($a[1],0,1) eq "\"");
     $a[0] = substr($a[0],0,-2) if (substr($a[0], -2) eq ".0");
     $a[1] =~ s/Counter\d\d\://;
     $R{"system.$a[0]"} =  $a[1];
  }



  ($err0,$sensors) = Util->run_command("$DIR/snmpwalk $OPT $ip public connUnitSensorType.$mibwwn", 
                      "sanbox_version.txt", $TO+5);

  my($sensor,  $name);
  my($max) = 0;
  my( @T, %CNT, @MAP);
  foreach my $x (@$sensors) {
     next if ($x !~ /$mibwwn/);
     $x =~ /(.*)\.(\d+) = (.*)/;
     my $name = $1; 
     my $ix   = $2; 
     my $val  = $3;
     $val =~ s/"//g;
     my $i = index($val,"(");
     $val = substr($val,0,$i) if ($i > 0);
     if ($name =~ /connUnitSensorType/) {
        $CNT{$val}++;
        $MAP[$ix] = "$val." . $CNT{$val};
     }
  }

  ($err0,$sensors) = Util->run_command("$DIR/snmpwalk $OPT $ip public connUnitSensorStatus.$mibwwn", 
                      "sanbox_version.txt", $TO+5);


   foreach my $x (@$sensors) {
     next if ($x !~ /$mibwwn/);
     $x =~ /(.*)\.(\d+) = (.*)/;
     my $name = $1; 
     my $ix   = $2; 
     my $val  = $3;
     $val =~ s/"//g;
     my $i = index($val,"(");
     $val = substr($val,0,$i) if ($i > 0);
     my $ix2 = $MAP[$ix];
     if ($name =~ /connUnitSensorStatus/) {
        $R{"sensor.$ix2.status"} = $val;
     } 
     $max = $ix if ($ix > $max);
  }


  ($err0,$sensors) = Util->run_command("$DIR/snmpwalk $OPT $ip public connUnitSensorName.$mibwwn", 
                      "sanbox_version.txt", $TO+5);


   foreach my $x (@$sensors) {
     next if ($x !~ /$mibwwn/);
     $x =~ /(.*)\.(\d+) = (.*)/;
     my $name = $1; 
     my $ix   = $2; 
     my $val  = $3;
     $val =~ s/"//g;
     my $i = index($val,"(");
     $val = substr($val,0,$i) if ($i > 0);
     my $ix2 = $MAP[$ix];
     if ($name =~ /connUnitSensorName/) {
        $R{"sensor.$ix2.name"} = $val;
     }
  }


  $R{"sensor.count"} = $max;

   # Get switch uptime
   my($err8,$uptime) = Util->run_command("$DIR/snmpwalk $OPT $ip public sysuptime ", 
                       "sanbox_version.txt", $TO+5);

  foreach my $x (@$uptime) {
     my(@a) = split(/\(/, $x);
     my(@b) = split(/\)/, $a[1]);
     $R{"system.uptime"} =  $b[0];

  }



  
  $agent->getStats($device, \%R);
  $agent->getLinks($device, \%R);
  $agent->getPortStatus($device, \%R);

  $agent->addIdentification(\%R);
  my $Version = $agent->getVersion($device);
  foreach my $el (keys %$Version) {
     $R{"info.version.$el"} = $Version->{$el};
  }



  $R{"id.wwn"} = $device->{wwn};

  return (undef, $R{"id.wwn"}, \%R);
}


sub FCCounters {
  my($class,$arg) = @_;

  return $class->switchFCCounters("switch2", $arg);
}

sub DESTROY {}


sub FCfromDevice {
  my($class, $dev) = @_;

  #$dev->{baseZero} = 1;
  #return Agent::SWITCH->FCfromDevice($dev);

  my (%X, @R, $x);
  my $renv = System->get_renv();
  my $DIR = System->get_home() . "/snmp/bin";
  my $TO = 10;
  my $max = 0;

  my $passwd;
  if ($dev->{telnet}) {
    $passwd = Util->decode($dev->{telnet});
  }

  my $SDIR = System->get_home() . "/sbin" ;
  my($err,$rem) = Util->run_command( "$SDIR/qlogiccounters $dev->{ipno} $passwd", 
                      "sanbox_version.txt", $TO+5, {cache => 0} );
  foreach my $l (@$rem) {
    if ($l =~ /(\d+)\.(\d+)\s*=\s*(\d+)/) {
       my $port = $1;
       my $fc_no = $2;
       my $val = $3;
       $R[$port][$fc_no] = $val;
       $max = $port if ($port > $max);
    }
  }

  for ($x=0; $x <= $max; $x++) {
      my $key = "|$dev->{key}|port.$x|switch";
      next if (!defined($R[$x]));

      $X{$key} = ($R[$x][1]+0) . "\t" .
                 ($R[$x][2]+0) . "\t" .
                 ($R[$x][3]+0) . "\t" .
                 ($R[$x][4]+0) . "\t" .
                 ($R[$x][5]+0) . "\t" .
                 ($R[$x][6]+0) . "\t" . 
                 ($R[$x][7]+0) . "\t" . 
                 ($R[$x][8]+0) . "\t";

  }
  return {enc => {$dev->{wwn} => $dev->{name}} , data => \%X };


  if (0) {

  my($MIBS)  = System->get_home() . "/snmp/mibs";
  my($OPT)   = "-r 0 -t $TO -m all -Osb ";
  my $ip = $dev->{ipno} || $dev->{ip};
  my $wwn    = $dev->{wwn};
  my $mibwwn = Util->wwn2mib($wwn);
  my $cnt = 1;
  my($err5, $errors) = Util->run_command("$DIR/snmpwalk $OPT $ip public fcFxPortName");
  my %ENC;
  my $enc_no;
  foreach my $l (@$errors) {
     if ($l =~ /(\d+)\.(\d+) = Hex: (.+)/) {
          my $lwwn = $3;
          $lwwn =~ s/ //g;
          $lwwn  = lc($lwwn);
          $lwwn = substr($lwwn,4);
          my $port = $2;
          $enc_no = $1;
          if ($port == 1) {
            last if (substr($wwn,4) eq $lwwn);
          }
      }
  }

  my(@ALL, @R); 

  # CRC
  my($err,$fc) = Util->run_command( 
          "$DIR/snmpwalk $OPT $ip public .1.3.6.1.2.1.75.1.3.1.1.6.$enc_no", "sanbox_version.txt", $TO+5);
  $ALL[4] = $fc;

  # ITW
  my($err,$fc) = Util->run_command( 
          "$DIR/snmpwalk $OPT $ip public .1.3.6.1.2.1.75.1.3.1.1.5.$enc_no", "sanbox_version.txt", $TO+5);
  $ALL[6] = $fc;
  # IN
  my($err,$fc)  = Util->run_command( 
          "$DIR/snmpwalk $OPT $ip public mib-2.75.1.4.3.1.1.$enc_no", "sanbox_version.txt", $TO+5);
  $ALL[7] = $fc;

  # OUT
  my($err,$fc) = Util->run_command( 
          "$DIR/snmpwalk $OPT $ip public mib-2.75.1.4.3.1.2.$enc_no", "sanbox_version.txt", $TO+5);
  $ALL[8] = $fc;

  foreach my $order (4,6,7,8) {
     my $values = $ALL[$order];
     foreach my $l (@$values) {
       if ($l =~ /\.(\d+) = Counter32: (\d+)/) {
         my $port = $1 - 1;
         my $val = $2;
         $R[$port][$order] = $val;
         $max = $port if ($port > $max);
       }
     }
  }
  }

}


sub REPORT {
  my($class, $host, $r, $arg) = @_;

  my($out);
  my($tableCnt) = $arg->{tableCnt};
  my($v) = $r->content();

  $out .= $class->reportHead("SWITCH2", $r);

   if(exists($v->{"id.connect_errs"})){
     print "<b><font color=red>NOTE: Errors were encountered when this report was generated. The data being displayed could be from an old report.</font></b>";
  }


  my($version) = $v->subset("info.version.");
  my($cnt) =0;
  $out .= "<tr><td align=right bgcolor=#F0F0F0><b>Product:<td>&nbsp;$v->{'info.Product'}</td>".
          "<td align=right bgcolor=#F0F0F0><b>IP:<td>&nbsp;$v->{'id.ipno'}</td>";
  $out .= "<tr><td align=right bgcolor=#F0F0F0><b>Status:<td>&nbsp;$v->{'info.Status'} / $v->{'info.State'}</td>".
          "<td align=right bgcolor=#F0F0F0><b>SerialNo:<td>&nbsp;$v->{'info.Sn'}</td>";

  foreach my $x (sort keys %$version) {
    $out .= "<tr>" if ($cnt++ % 2 == 0);
    my $x0 = $x;
    $x0 =~ s/Version//;
    $x0 =~ s/_/ /g;
    $out .= "<td align=right bgcolor=#F0F0F0><b>$x0:<td>&nbsp;$version->{$x}</td>";
  }
  $out .= "</table><table border=1 cellspacing=0 width=100% bgcolor=white>";

  my $x;
  $out .= "<tr bgcolor=#CCCCFF><th>Sensor<th>Status<th colspan=2>Description</th>";
  foreach my $el ('board','fan','power-supply') {
    for ($x = 1; $x <= 10; $x++) {
       my $name = $v->{"sensor.$el.$x.name"};
       next if (!$name);
       my $status = $v->{"sensor.$el.$x.status"};
       my $desc = $v->{"sensor.$el.$x.message"};
       $out .= "<tr><td>&nbsp;$name<td>&nbsp;$status<td colspan=2>&nbsp;$desc</td>";
    }
  }

  $out .= "</table><table border=1 cellspacing=0 width=100% bgcolor=white>";
  $out .= "<tr bgcolor=#CCCCFF><th>Port<th>State<th>Type<th>Speed</th>";
  for ($x=0; $x <= 64; $x++) {
     my $type   = $v->{"port.$x.type"};
     my $speed  = $v->{"port.$x.speed"};
     my $state  = $v->{"port.$x.state"};
     last if (!$type);
     $out .= "<tr><td>&nbsp;$x<td>&nbsp;$state<td>&nbsp;$type<td>&nbsp;$speed</td>";
  }

  if (!$tableCnt) {
    $out .= "</table>";
  }
  return $out;

}



sub REPORT2 {
  my($class, $host, $r, $arg) = @_;

  my($out);
  my($v) = $r->{_value};

  my $last;
  $out = $class->reportHead("Sun Switch2", $r);
  foreach my $el (sort keys %$v) {
     my($a, $b) = split(/\./, $el);
     if ($a ne $last) {
        $out .= "<tr bgcolor=#CCCCFF><td colspan=2>&nbsp;<b>$a</td>\n" if ($a);
        $last = $a;
     }

     $out .= "<tr><td>&nbsp;$el<td>&nbsp;$v->{$el}</td>";
  }
  $out .= "</table>";
  return $out;

}


sub getZones {
  my($class, $DIR, $s_ip, $TO, $V, $dev) = @_;
  my($err);
  my $totzones;
  $totzones = -1;
  my $password = Util->decode($dev->{telnet});
  my($err1,$info) = Util->run_command("$DIR/qlogicswitchzones $s_ip $password", "sanbox_status.txt", $TO);
  $err .= $err1;

  foreach my $l (@$info) {
     if ($l =~ /Number of members/) {
        $totzones++;
     } elsif ($l =~ /Port = (\d+)/) {
        my $po = $1;
        $V->{"zone.hd.$totzones.members"} .= "$po ";
     }
  }
     $V->{"zone.total"} = $totzones;

  return $err;

}



1;
