package Inventory;
use strict;
use System;
use Agent::T3;
use Agent::3510;
use Agent::3310;
use Agent::6020;
use Agent::VE;
use Logic::SWITCH;

# $Id: Inventory.pm,v 1.8 2005/02/28 23:10:43 kdesai Exp $

use vars qw($GRIZ $INDY1 $INDY2 $MASER $VMPATH $VM_TO $SYSTEM1HELP $MIDRANGEHELP $INDYHELP);

$INDY1 = ",3910,3960,6910,6960,3900SL,6910SL,6960SL,";
$INDY2 = ",3975,6965,6975,";
$MASER = ",6320,6920,6970,";
$GRIZ  = ",5510,";
$VMPATH = "/usr/bin/perl -U /opt/se6x20";
$VM_TO  = 2 * 60;
$SYSTEM1HELP = "SystemOneHelp";
$MIDRANGEHELP= "UnityHelp";
$INDYHELP    = "IndyHelp";  # FIX LATER

sub goldenName {
  return System->get_home() . "/DATA/Inventory.golden";
}

sub log {
  my($class, $text) = @_;
  open(O, ">>" . System->get_home(). "/log/Service.log");
  my $date = Util->get_today();
  print O "$date\t$text\n";
  close(O);
}

sub writeInventory {
   my($inv, $file, $HTML, $skip_vmcfg) = @_;
   $file = $inv->goldenName() if (!$file);
   open(O, ">$file");
   require Data::Dumper;
   $Data::Dumper::Indent = 1;
   print O Data::Dumper::Dumper($inv);
   close(O);
   if ($inv->{solution} eq "se2" && !$skip_vmcfg) {
      print "Running vmcfg...";
      print $HTML ? "<br>" : "\n";
      $inv->run_vmcfg($HTML);
   }
}

sub readInventory {
  my($class, $file) = @_;
  $file = $class->goldenName() if (!$file);

  if (open(O, $file)) {
     my @L = <O>; close(O);
     my $VAR1;
     eval "@L";
     return $VAR1;
  }
  return undef;
}

sub getKeys {
  my($inv) = @_;
  my %K;
  my $devs = $inv->{devices};
  foreach my $d (@$devs) {
     $K{$d->{key}} = $d;
  }
  return \%K;
}

sub deviceCount {
  my($inv) = @_;
  my $devs = $inv->{devices};
  return $#$devs + 1;
}


sub getDevices {
  my($inv) = @_;
  return $inv->{devices};
}

#  $inv = Inventory->read();
#  print $inv->toXML();

sub toXML {
  my($inv) = @_;
  
  my $out =<<EOF;
<?xml version=\"1.0\"?>
<!DOCTYPE inventory PUBLIC "-//Sun Microsystems//DTD XML Version 1.0//EN" "/opt/SUNWstade/System/Inventory.dtd">
<inventory>
  <created>$inv->{created}</created>
  <created2>$inv->{created2}</created2>
  <model>$inv->{model}</model>
  <solution>$inv->{solution}</solution>
EOF
  my $devs = $inv->{devices};
  foreach my $d (@$devs) {
     $out .= "  <device type=\"$d->{type}\">\n";
     my $att;
     foreach my $k (sort keys %$d) {
         if (index(",last_update,class,key,ip,name,wwn,", ",$k,") >= 0) {
            $out .= "    <$k>$d->{$k}</$k>\n";
         } elsif ($k ne "type" && $k ne "frus") {
            $att .= "    <attribute id=\"$k\">$d->{$k}</attribute>\n";
         }
     }
     $out .= $att;
     my $frus = $d->{frus};
     foreach my $f0 (sort keys %$frus) {
        my $f = $frus->{$f0};
        my $extra;
        foreach my $el ('loopVersion','ctlrVersion') {
          $extra .= " <$el>$f->{$el}</$el>" if (exists $f->{$el});
        }

        if (length($f->{serialNo}) > 1) {            # t3/t4
          $out .=<<EOF;
          <component type="$d->{type}">
            <fruId>$f0</fruId>
            <fruModel>$f->{model}</fruModel>
            <fruRevision>$f->{revision}</fruRevision>$extra
            <fruSerialNo>$f->{serialNo}</fruSerialNo>
            <fruVendor>$f->{vendor}</fruVendor>
          </component>
EOF
        } elsif (exists $f->{serialNumber}) {  # dsp
          my $rev = "$f->{hWRev}.$f->{pCBRev}" if ($f->{hWRev});
          $out .=<<EOF;
          <component type="$d->{type}">
            <fruId>$f0</fruId>
            <fruClass>$f->{class}</fruClass>
            <fruModel>$f->{partNumber}</fruModel>
            <fruRevision>$rev</fruRevision>$extra
            <fruSerialNo>$f->{serialNumber}</fruSerialNo>
            <fruState>$f->{state}</fruState>
            <fruVendor>SUN</fruVendor>
          </component>
EOF
        } else {                                   # sp
          $out .=<<EOF;
          <component type="$d->{type}">
            <fruId>$f0</fruId>
            <fruModel>$f->{model}</fruModel>
            <fruRevision>$f->{revision}</fruRevision>$extra
            <fruSerialNo>$f->{serialNo}</fruSerialNo>
            <fruVendor>SUN</fruVendor>
          </component>
EOF
        }
     }
     $out .= "  </device>\n";
    
  }
  $out .= "</inventory>\n";
  return $out;
}


sub findCurrentModel {
  my($class) = @_;
  my $inv = $class->readInventory();
  return $inv->{model};
}

sub readHostLines {
  my($class) = @_;

  if (open(O, "/etc/hosts")) {
    my @host_lines = <O>;
    close(O);
    return \@host_lines;
  } else {
    print "Error: Cannot read /etc/hosts, aborting \n";
    return undef;
  }
}

sub run_vmcfg {
  my($inv, $HTML) = @_;
  my($renv, $devs, $hosts,$notifs) = PDM::ConfigFile->read();
  my(%F, $errs, $info);

  my $devices = $inv->{devices};
  foreach my $r (@$devices) {
      if ($r->{type} eq "dsp"){
	 my($err, $rc) = $inv->run_vmcfg0($r->{ipno}, "configure", "dsp");
         if ($err) {
            $errs .= "DSP $r->{ipno} ERROR: $err";
            $errs .= $HTML ? "<br>" : "\n";
         } else {
            $info .= "DSP $r->{ipno}: configured for use.";
            $info .= $HTML ? "<br>" : "\n";
         }

      }

      next if ($r->{type} ne "6020");
      my $cool;
      require Service::Array;
      my $rc = Service::Array->add($r->{ipno});

      if ($rc) {
         $errs .= $rc;
         $errs .= $HTML ? "<br>" : "\n";
      } else {
         $errs .= $rc;
         $errs .= $HTML ? "<br>" : "\n";
         my($err, $rc) = $inv->run_vmcfg0($r->{ipno});
         if ($err) {
            $errs .= "Array $r->{ipno} ERROR: $err $err Check password";
            $errs .= $HTML ? "<br>" : "\n";
         } else {
            $info .= "Array $r->{ipno}: configured for use.";
            $info .= $HTML ? "<br>" : "\n";
         }
      }
  }
  print $info . $errs;
}

sub run_vmcfg0 {
  my ($class, $ip, $command, $type) = @_;

  $command = "configure" if (!$command);
  $type = "t4" if (!$type);

  my $array_p = System->getPassword("array");
  my $tell = (stat("/var/adm/messages"))[7];
  
  #print "vmcfg $command -t t4 -i $ip <br>";

  my ($err, $rc, $error) = Util->run_command("$VMPATH/bin/vmcfg $command -t $type -i $ip -u root -p $array_p", "vmcfg", $VM_TO, 
     {           cache => 0, 
       display_command =>  "vmcfg $command -t $type -i $ip -u root -p x",
     });

  open(FILE_F1, "/var/adm/messages");
  seek(FILE_F1, $tell, 0);
  my ($trace, $line);
  for ($tell = tell(FILE_F1); $line = <FILE_F1>; $tell = tell(FILE_F1)) {
    $trace .= $line;
  }
  close(FILE_F1);

  return ("$err$error" , $rc, $trace);
}
  

# SAVE SNAPSHOT TO RASAGENT.conf
#
sub writeConfig {
   my($inv, $mode) = @_;
   my %F;
   # mode is append or write
   my($renv, $devs, $hosts,$notifs) = PDM::ConfigFile->read();
   if ($mode eq "append") {
     foreach my $d (@$devs) {
       $F{$d->{key}} = 1;
     }
   } elsif ($mode eq "write") { # new devs
     $devs = [];
   }
   my $add;
   my $devices = $inv->{devices};
   foreach my $r (@$devices) {
       next if ($F{$r->{key}});
       next if ($r->{type} eq "sp");
       $F{$r->{key}} = 1;
       my $no = $#$devs + 1;
       my $new = {};
       foreach my $el (keys %$r) {
         $new->{$el} = $r->{$el} if (substr($el,0,1) ne "_" && $el ne "frus");
       }
       $new->{_name} = "device" . $no;
       $new->{mgmtLevel} = "C";
       if ($r->{type} eq "t3") {
          $new->{userLabel} = Agent::T3->getUserLabel($new->{ctrl_model});
       }
       $new->{active} = "Y";
       push(@$devs, $new); $add++;
   }
   $renv->{cust_no}  = $inv->{serial_no} if ($inv->{serial_no});
   $renv->{solution} = $inv->{solution};
   $renv->{solution_model} = $inv->{model};
   $renv->{categories} = "sp|message|t3message|san";
   $renv->{categories} .= $inv->{solution} eq "se" ? 
                             "|switch|switch2|3510|t3|sve2|ve" : "|6020|dsp|t3";

   $renv->{t300logfile} = "/var/adm/messages.t3";

   $renv->{customer}     = "NWS_OPS" if (!$renv->{customer});
   $renv->{site_name}    = "ops"     if (!$renv->{site_name});
   $renv->{site_city}    = "Newark"  if (!$renv->{site_city});
   $renv->{site_zip}     = "98765"   if (!$renv->{site_zip});
   $renv->{site_country} = "USA"     if (!$renv->{site_country});
   $renv->{site_contact} = "ops"     if (!$renv->{site_contact});
   $renv->{site_email}   = "root\@localhost"    if (!$renv->{site_email});
   delete $renv->{role};
   $renv->{window}       = "B";
   if ($inv->{solution} eq "se2") {
      $renv->{window}     = "N";
      $renv->{sun_help}   = $SYSTEM1HELP;
      $renv->{t300logfile}= &find_log();
      $renv->{dsp_logfile}= "/var/adm/messages.dsp";
      #if(! -d "/opt/SUNWstade/htdocs/Help/english"){
      #   system("/usr/bin/ln -s /opt/SUNWse9help/Help/english  /opt/SUNWstade/htdocs/Help/english");
      #} take this out help should already be installed
   }elsif ($inv->{solution} eq "se") {
      $renv->{sun_help}     = $INDYHELP;
      $renv->{t300logfile}  = "/var/adm/messages.t3";
   } else {
      $renv->{t300logfile}= "/var/adm/messages.t300";
   }
   open(O, ">" . System->get_home() . "/DATA/start");
   close(O);
   $renv->{active} = "Y";

   my %new2;
   my $sekey = $inv->{model} . "." . System->hostid();

   if ($inv->{solution} eq "se99") {
     $renv->{window}         = "N";
     $sekey = $inv->{model} . "." . $inv->{serial_no};
     $renv->{active_cluster} = 1;
     $renv->{categories}     = "sp|host|switch2|3510|3511";
   }


   if ($add && !$F{$sekey}) { # add the rack itself
       my $ipno = Util->name2ip();
       my $no = $#$devs + 1;
       $new2{_name}   = "device" . $no;
       $new2{type}     = $inv->{solution};
       $new2{class}   = "storage.$inv->{solution}";
       $new2{name}     = $inv->{model} . "-" . $renv->{hostname};
;
       $new2{ip}       = $ipno;
       $new2{wwn}      = $sekey;
       $new2{key}      = $sekey;
       $new2{model}    = $inv->{model};
       $new2{mgmtLevel}= "DS";
       $new2{ipno}     = $ipno;
       $new2{active}   = "Y";
       $new2{time_added} = Util->get_today();

       push(@$devs, \%new2);
    }
    PDM::ConfigFile->write( $renv, $devs, $hosts, $notifs) if ($add);
}


sub find_log {
  my ($l,$file);
  if (open(OO, "/etc/syslog.conf")) {
     while ($l = <OO>) {
          if ($l =~ /^local7\.\w+\s+(.+)/) {
             $file = $1; last;
          }
     }
     close(OO);
  }
  return $file;
}

# Update snmp info.
# /opt/SUNWstade/snmp/share/snmp/sys.conf
# sysDescr=Sun StorEdge Solution 3900/6900
# sysObjectID=42.2.28.13.2

sub writeSnmpConfig {
   my($inv) = @_;
   my $solution = $inv->{solution};
   my $model    = $inv->{model};

   open(O, ">/opt/SUNWstade/snmp/share/snmp/sys.conf");
   print O "sysDescr=Sun StorEdge Solution $model\n";
   my $last = $solution eq "se" ? "1" : "2";
   print O "sysObjectID=42.2.28.13.$last\n";
   close(O);
}

#======================================================================

sub check_t3 {
  my($rc, $default_type, $trace_out, $golden, $short, $T,$ip, $ipno, $trace,
     $userLabel) = @_;
  my($next);
  my $warn;
  if (!$rc->{key} && !$rc->{wwn} && !$rc->{wwn2} && !$rc->{ctrl_model} ) {
     my $o = "  -> Error: Could not retrieve tokens from this array\n";
     $$trace_out .= $o; print $o;
     #next; 
  }
  if ($default_type ne $rc->{type}) {
     my $o = "  -> Warning : type is '$rc->{type}', should be '$default_type'\n";
     $warn++;
     $$trace_out .= $o; print $o;
  }
  if (!$rc->{key}) {
     my $o = "  -> Error: cannot find the serial# of this array\n";
     $$trace_out .= $o; print $o if ($trace);
  } 
  if (!$rc->{wwn}) {
     my $o = "  -> Error: cannot find the wwn of the first port of this array\n";
     $$trace_out .= $o; print $o if ($trace);
  } 
  if (!$rc->{wwn2}) {
     my $o = "  -> Error: cannot find the wwn of the second port of this array\n";
     $$trace_out .= $o; print $o if ($trace);
  } 
  if (!$rc->{wwn} || !$rc->{key}) {
     $next = 1;
  } else {
      my (%FRUS);
      $T->{report_t3} .= "$ip, ";
      $T->{t3_cnt}++;
      foreach my $x (keys %$rc) {
           if (substr($x,0,4) eq "FRU.") { 
              my ($xx, $id, $name) = split(/\./, $x);
              $name = substr($name,3) if (substr($name,0,3) eq "fru");
              $name = lcfirst($name);
              $FRUS{$id}{$name} = $rc->{$x};
           }
      }
      my $time_a = Util->get_today();

      push(@$golden, bless({
            type => $rc->{type}, class => "storage.$rc->{type}",
            ip   => $ipno,
            ipno => $ipno,
            name => $ip,
            userLabel => $userLabel,
            key  => $rc->{key},
            units => $rc->{units},
            wwn  => $rc->{wwn},
            wwn2 => $rc->{wwn2},
            sysRevision => $rc->{"SYSTEM.sysRevision"},
            ctrl_model => $rc->{ctrl_model},
	    time_added => $time_a,
            frus   => \%FRUS },'Inv_dev') );

      my $o = "  -> found $rc->{type} ($ipno / $rc->{wwn}/$rc->{wwn2}\n\t\t$rc->{key}) \n";
      $trace_out .= $o; 
      print $o ;
  }
  return $warn;
}

sub check_dsp {
  my($rc, $default_type, $trace_out, $golden, $short, $T,$ip, $ipno, $trace,
     $userLabel) = @_;
  my($next);
  my $warn;

  if ($default_type ne $rc->{type}) {
     my $o = "  -> Warning : type is '$rc->{type}', should be '$default_type'\n";
     $warn++;
     $$trace_out .= $o; print $o;
  }
  if (!$rc->{key}) {
     my $o = "  -> Error: cannot find the serial# of this array\n";
     $$trace_out .= $o; print $o if ($trace);
  } 
  if (!$rc->{key}) {
     $next = 1;
  } else {
      my (%FRUS);
      $T->{report_sve} .= "$ip, ";
      $T->{sve_cnt}++;
      foreach my $x (keys %$rc) {
           if (substr($x,0,4) eq "FRU.") { 
              my ($xx, $id, $name) = split(/\./, $x);
              $name = substr($name,3) if (substr($name,0,3) eq "fru");
              $name = lcfirst($name);
              $FRUS{$id}{$name} = $rc->{$x};
           }
      }
      my $time_a = Util->get_today();
      push(@$golden, bless({
            type      => $rc->{type}, 
            class     => "switch.$rc->{type}",
            ip        => $ipno,
            ipno      => $ipno,
            name      => $ip,
            userLabel => $userLabel,
            key       => $rc->{key},
            units     => $rc->{units},
            wwn         => $rc->{wwn},
            sysRevision => $rc->{"SYSTEM.sysRevision"},
	    time_added => $time_a,
            frus        => \%FRUS },
              'Inv_dev') );

      my $o = "  -> found $rc->{type} ($ipno / $rc->{wwn} / $rc->{key}) \n";
      $trace_out .= $o; 
      print $o ;
  }
  return $warn;
}

sub check_3510 {
  my($rc, $default_type, $trace_out, $golden, $short, $T,$ip, $ipno, $trace) = @_;
  my($next);
  my $warn;
  if (!$rc->{key}) {
     my $o = "  -> Error: Could not retrieve tokens from this array\n";
     $$trace_out .= $o; print $o;
     #next; 
  }
  if ($default_type ne $rc->{type}) {
     my $o = "  -> Warning : type is '$rc->{type}', should be '$default_type'\n";
     $warn++;
     $$trace_out .= $o; print $o;
  }

  if (!$rc->{key}) {
     $next = 1;
  } else {
      my (%FRUS);
      $T->{report_t3} .= "$ip, ";
      $T->{t3_cnt}++;
      foreach my $x (keys %$rc) {
           if (substr($x,0,4) eq "FRU.") { 
              my ($xx, $id, $name) = split(/\./, $x);
              $name = substr($name,3) if (substr($name,0,3) eq "fru");
              $name = lcfirst($name);
              $FRUS{$id}{$name} = $rc->{$x};
           }
      }
      my $time_a = Util->get_today();

      push(@$golden, bless({
            type  => $rc->{type}, class => "storage.$rc->{type}",
            ip    => $ipno,
            ipno  => $ipno,
            name  => "$short-$ip",
            key   => $rc->{key},
            units => $rc->{units},
            wwn   => $rc->{key},
            wwns  => $rc->{wwns},
            userLabel => $rc->{model},
	    time_added => $time_a,
            frus   => \%FRUS },'Inv_dev') );

      my $o = "  -> found $rc->{model} ($ipno / $rc->{wwns}\n\t\t$rc->{key}) \n";
      $trace_out .= $o; 
      print $o ;
  }
  return $warn;
}

#########################################################################
#  GRIZABELLA
#########################################################################

sub readGriz {
 my($class, $short, $PREFIX, $trace, $HTML, $TO, $MODEL, $SERIAL) = @_;
 my $golden = [];
 my $xml;
 my ( $trace_out, %T);
 my $lines = Inventory->readHostLines();
 $PREFIX = "192.168" if (!$PREFIX);
 if (!$SERIAL) {
   my $err = "Serial Number is required. use config_solution -S [serial_no] .";
   $trace_out .= $err; print $err;
   $T{err}++;
   my $INV = { stats => \%T };
   bless($INV, 'Inventory');
   return ($trace_out, $INV);
 }

 my $time_a = Util->get_today();
 my $IN;
 foreach my $l (@$lines) {
    chop($l);
    $IN = 1 if ($l =~ /^#\s*GRIZ/);
    next if (!$IN);
    next if (substr($l,0,1) eq "#");
    my ($ipno, $ip, $rest) = split(/\s+/, $l);
    next if (!$ipno);
    next if (substr($ipno,0,length($PREFIX) ) ne $PREFIX);
    my @nos = split(/\./, $ipno);
    my $no = $nos[3];
    print "<br>" if ($HTML);
    print "$ip: \n";

    if ($ip =~ /Array\d+/) { # 3510, 3511
       if (&ping($ipno)) {
          my $rc = Agent::3310->getFastWWN($ipno, undef, 1);
          if ($rc->{error}) {
            print $rc->{error} . "\n";
            $T{err} += 1;   # should be err eventually
          }
          my $warn = &check_3510($rc, $rc->{type}, \$trace_out, $golden, $short, \%T,$ip, $ipno,  $trace);
          $T{warn} += $warn;
  
       } else {
          my $o = "  -> Warning: cannot ping $ipno \n";
          $o .= "     Device is not responding or not present in this configuration\n";
          $trace_out .= $o; print $o if ($trace);
       }
           
    } elsif ($ip =~ /Switch\d+/) {  # qlogic switches
       if (&ping($ipno)) {
          my($wwn, $type, $ports, $rev) = &findSwitch($ipno);
          if (!$wwn) {
             my $o =  "  -> Error: cannot find the wwn of $ipno \n";
             $trace_out .= $o; print $o;
             $T{err}++;
          } else {
              if (!$T{sw_ports}) {
                $T{sw_ports} = $ports;
                if ($T{sw_ports} != 16) {
                    print "  -> switch $ipno, invalid # ports: $T{sw_ports}\n";
                    $T{err}++;
                }
              }
              $T{report_sw} .= "$ip, ";
              $T{sw_cnt}++;
              push(@$golden,bless( {
                    type => $type, class => "switch.$type",
                    ip   => $ipno,
                    ipno => $ipno,
                    name => "$short-$ip",
                    key  => $wwn,
                    wwn  => $wwn,
                    ports => $T{sw_ports},
		    time_added => $time_a,
                    frus  => { $ip => {
                                 vendor   => "SUN",
                                 serialNo => $wwn,
                                 model    => "SUN-$type",
                                 revision => $rev, 
                                      }}}, 'Inv_dev') );
              my $o = "  -> found $type ($ipno / $wwn) \n";
              $trace_out .= $o; 
              print $o;
          }
  
       } else {
          my $o = "  -> Warning: cannot ping $ipno \n";
          $o .= "     Device is not responding or not present in this configuration\n";
          $trace_out .= $o; print $o if ($trace);
       }
   }
 }
 my $date = Util->get_today();
 my $date2 = `date`;
 chop($date2);
 my $INV = { created => $date, 
           created2 => $date2, 
           solution => "se99",
              stats => \%T,
            devices => $golden,
          };
 bless($INV, 'Inventory');
 return ($trace_out, $INV);
}


#  MODEL : requested model
#
sub validateGriz {
 my($inv, $MODEL, $trace) = @_;

  my ($prefix, $suffix, $trace_out, $model);
  my $T = $inv->{stats};

  $model = $MODEL;

  $inv->{model} = $model;
  my $w_info = "|Warn(s) : $T->{warn}\n" if ($T->{warn});
  $T->{sw_cnt} += 0;
  my $summary =<<EOF;
  
=====================================
|     Configuration Summary         |
-------------------------------------
|  Model : $model, Requested = $MODEL
|  Switch: $T->{sw_cnt}, ports=$T->{sw_ports}
|        : $T->{report_sw}
|  Arrays: $T->{t3_cnt} 
|        : $T->{report_t3}
$w_info
=====================================
EOF

  return ($T->{err},$trace_out, $summary);
}



#########################################################################
#  INDY 
#########################################################################

sub readIndy {
 my($class, $short, $PREFIX, $PASS, $trace, $HTML, $TO) = @_;
 my $golden = [];
 my $xml;
 my ( $trace_out, %T);
 my $lines = Inventory->readHostLines();
 $PREFIX = "192.168" if (!$PREFIX);

 my $time_a = Util->get_today();
 foreach my $l (@$lines) {
    chop($l);
    next if (substr($l,0,1) eq "#");
    my ($ipno, $ip, $rest) = split(/\s+/, $l);
    next if (!$ipno);
    next if (substr($ipno,0,length($PREFIX) ) ne $PREFIX);
    my @nos = split(/\./, $ipno);
    my $no = $nos[3];
    print "<br>" if ($HTML);
    print "$ip: \n";

    if ($no >= 20 && $no <= "23") { # vicom
         if (!&ping($ipno)) {
             my $o = "  -> Warning: cannot ping $ipno \n";
             $o .= "     Device is not responding or not present in this configuration\n" ;
             $trace_out .= $o;
             print $o if ($trace);
             next;
         }
         $T{ve_cnt}++;
         my $wwn = Agent::VE->getWWN($ipno, undef, 20, $PASS);
         my $login = ($no <= 21)? "v1":"v2";
	 my $init = "1";
         if($no == 21){
           $init = "2";
         }elsif($no == 22){
           $init = "1";
         }elsif($no == 23){
           $init = "2";
         }
	 

         if (length($wwn) > 10) {
           $T{report_ve} .= "$ip, ";
           push(@$golden, bless( {
                    type => "ve", class => "switch.ve",
                    ip   => $ipno,
                    ipno => $ipno,
                    key  => $wwn,
                    name => "$short-$ip",
                    wwn  => $wwn,
		    time_added => $time_a,
                    login => $login, initiator => $init,
                    frus  => { $ip => {
                                 vendor   => "SUN",
                                 serialNo => "1000",
                                 model    => "VICOM",
                                 revision => "REV", 
                                          }}},'Inv_dev') );
  
           my $o  = "  -> found VE ($ip / $ipno / $wwn) \n";
           $trace_out .= $o; 
           print $o;
  
         } else {
           my $o = "  -> Error: cannot telnet to VEs at $ip/$ipno (remove password if present)\n";
           $trace_out .= $o; print $o;
           $T{err}++; next;
         }
  
     } elsif ($no >= 25 && $no <= 29) { # PSX=1000
         if (!&ping($ipno)) {
             my $o = "  -> Warning: cannot ping $ipno \n";
             $o .= "     Device is not responding or not present in this configuration\n" ;
             $trace_out .= $o;
             print $o if ($trace);
             next;
         }
         $PASS = "pirus" if (!$PASS);
         my $PASS_encoded = Util->encodeAll($PASS);

         $T{ve_cnt}++;
         require Agent::SVE2;
         my $wwn = Agent::SVE2->getWWN( 
                      {ipno => $ipno, login => "root", telnet => $PASS_encoded});

         if (length($wwn) > 10) {

           $T{report_ve} .= "$ip, ";
           push(@$golden, bless( {
                    type => "sve2", class => "switch.sve2",
                    ip   => $ipno,
                    ipno => $ipno,
                    key  => $wwn,
                    name => "$short-$ip",
                    wwn  => $wwn,
               userLabel => 'DSP',
                   login => "root",
              time_added => $time_a,
                  telnet => $PASS_encoded,
                   frus  => { $ip => {
                                 vendor   => "SUN",
                                 serialNo => $wwn,
                                 model    => "DSP-1x00",
                                 revision => "REV", 
                                          }}},'Inv_dev') );
  
           my $o  = "  -> found SVE ($ip / $ipno / $wwn) \n";
           $trace_out .= $o; 
           print $o;
  
         } else {
           my $o = "  -> Error: cannot telnet to SVEs at $ip/$ipno (remove password if present)\n";
           $trace_out .= $o; print $o;
           $T{err}++; next;
         }
  
    } elsif ($no >= 40 && $no <= 54) { # T3
       if (&ping($ipno)) {
          my $rc = Agent::T3->getWWN($ipno, undef, $TO, 1);
          my $warn = &check_t3($rc, "t3", \$trace_out, $golden, $short, \%T,$ip, $ipno,  $trace, $rc->{userLabel});
          $T{warn} += $warn;
  
       } else {
          my $o = "  -> Warning: cannot ping $ipno \n";
          $o .= "     Device is not responding or not present in this configuration\n";
          $trace_out .= $o; print $o if ($trace);
       }

    } elsif ($no >= 60 && $no <= 75) { # MINNOW fcaXX
       if (&ping($ipno)) {
          my $rc = Agent::3310->getWWN($ipno);
          my $warn = &check_3510($rc, "3510", \$trace_out, $golden, $short, \%T,$ip, $ipno,  $trace);
          $T{warn} += $warn;
  
       } else {
          my $o = "  -> Warning: cannot ping $ipno \n";
          $o .= "     Device is not responding or not present in this configuration\n";
          $trace_out .= $o; print $o if ($trace);
       }
           
    } elsif ($no >= 30 && $no <= 33) { # switch
       if (&ping($ipno)) {
          my($wwn, $type, $ports, $rev) = &findSwitch($ipno);
          if (!$wwn) {
             my $o =  "  -> Error: cannot find the wwn of $ipno \n";
             $trace_out .= $o; print $o;
             $T{err}++;
          } else {
              if (!$T{sw_ports}) {
                $T{sw_ports} = $ports;
                if ($T{sw_ports} != 16 && $T{sw_ports} != 8) {
                    print "  -> switch $ipno, invalid # ports: $T{sw_ports}\n";
                    $T{err}++;
                }
              }
              $T{report_sw} .= "$ip, ";
              $T{sw_cnt}++;
              push(@$golden,bless( {
                    type => $type, class => "switch.$type",
                    ip   => $ipno,
                    ipno => $ipno,
                    name => "$short-$ip",
                    key  => $wwn,
                    wwn  => $wwn,
                    ports => $T{sw_ports},
		    time_added => $time_a,
                    frus  => { $ip => {
                                 vendor   => "SUN",
                                 serialNo => $wwn,
                                 model    => "SUN-$type",
                                 revision => $rev, 
                                      }}}, 'Inv_dev') );
              my $o = "  -> found $type ($ipno / $wwn) \n";
              $trace_out .= $o; 
              print $o;
          }
  
       } else {
          my $o = "  -> Warning: cannot ping $ipno \n";
          $o .= "     Device is not responding or not present in this configuration\n";
          $trace_out .= $o; print $o if ($trace);
       }
     }
   }
   my $date = Util->get_today();
   my $date2 = `date`;
   chop($date2);
   my $INV = { created => $date, 
           created2 => $date2, 
           solution => "se",
              stats => \%T,
            devices => $golden,
          };
   bless($INV, 'Inventory');
   return ($trace_out, $INV);
}

#  MODEL : requested model
#
sub validateIndy {
 my($inv, $MODEL, $trace) = @_;

 my ($prefix, $suffix, $trace_out, $model);
 my $T = $inv->{stats};

  if (substr($MODEL,0,2) eq "39" && $T->{ve_cnt} > 0) {
    my $o = "  -> Error: Found $T->{ve_cnt} ve, but model is $MODEL!\n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }
  
  if (($MODEL eq "6910" && $T->{ve_cnt} != 2) ||
      ($MODEL eq "6960" && $T->{ve_cnt} != 4)) { 
    my $o = "  -> Error: Wrong number of VE($T->{ve_cnt}) found for $MODEL! \n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }
  if ($T->{t3_cnt} == 0) {
    my $o = "  -> Warning: No Storage Array found! \n";
    $trace_out .= $o; print $o;
  }
  
  if ($T->{sw_ports} != 16 && substr($MODEL,2,2) eq "60") {
    my $o = "  -> Error: Model $MODEL need 16 port switches! \n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }
  
  if ($T->{sw_ports} != 8 && substr($MODEL,2,2) eq "10") {
    my $o =  "  -> Error: Model $MODEL need 8 port switches! \n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }
  if (index($INDY2, $MODEL) >= 0) {
     $model = $MODEL;
     

  } elsif (index($INDY1, $MODEL) >= 0) {
     my $sw1 = 2;
     my $sw2 = 4;
     if ($MODEL =~ /SL/) {
        $sw1 -= 2;
        $sw2 -= 2;
     }
     if ((substr($MODEL,0,2) eq "39" && $T->{sw_cnt} != $sw1) ||
         (substr($MODEL,0,2) eq "69" && $T->{sw_cnt} != $sw2)) {
       my $o = "  -> Error: Wrong number of switches ($T->{sw_cnt}) for a $MODEL \n";
       $trace_out .= $o; print $o;
       $T->{err}++;
     
     }
     
     $suffix = "XX";
     if ($T->{sw_ports} == 16) {
        $suffix = "60";
     } elsif ($T->{sw_ports} == 8) {
        $suffix = "10";
     } elsif ($T->{sw_cnt} == 0) {
        $suffix = "00";
     }
     my $sl;
     if ($T->{ve_cnt}) {
       $prefix = "69";
       $sl = "SL" if ($T->{sw_cnt} == 2);
     } else {
       $prefix = "39";
       $sl = "SL" if ($T->{sw_cnt} == 0);
     }
     $model = $prefix . $suffix . $sl;
        
     if ($MODEL && $MODEL ne $model) {
        my $o = "ERRORS: Model proposed ($MODEL) is different than discovered model ($model)\n";
        $trace_out .= $o; print $o;
        $T->{err}++;
     }
  }


  $inv->{model} = $model;
  my $w_info = "|Warn(s) : $T->{warn}\n" if ($T->{warn});
  $T->{sw_cnt} += 0;
  $T->{ve_cnt} += 0;
  my $summary =<<EOF;
  
=====================================
|     Configuration Summary         |
-------------------------------------
|  Model : $model, Requested = $MODEL
|  Switch: $T->{sw_cnt}, ports=$T->{sw_ports}
|        : $T->{report_sw}
|  Arrays: $T->{t3_cnt} 
|        : $T->{report_t3}
|  VEs   : $T->{ve_cnt} 
|        : $T->{report_ve}
$w_info
=====================================
EOF

  return ($T->{err},$trace_out, $summary);
}

#########################################################################
#  MASERATI
#########################################################################

sub upgradeMaserati {
  my($class, $HTML) = @_;

  my $inv     = Inventory->readInventory();
  if (!$inv) {
    return "ERR: Cannot read Inventory";
  }
     
  my $devices = $inv->{devices};
  my $TO      = 100;
  foreach my $d (@$devices) {
     if ($d->{type} eq "sp") {
        my ($ntc_version, $fire_version) = $class->read_versions();

     } elsif ($d->{type} eq "dsp") {
         require Agent::DSP;
         my $rc0  = Agent::DSP->getWWN($d->{ip}, undef, $TO, 1);
         my $rc   = $rc0->{report};
         my $frus = $d->{frus};
         foreach my $f0 (keys %$frus) {
           my @t = split(/_/, $frus->{$f0}{type});
           my $fru_type = $t[0];
           if ($rc->{"$fru_type.$f0.HWRev"}) {
             $frus->{$f0}{hWRev}  = $rc->{"FRU.$f0.HWRev"};
             $frus->{$f0}{pCBRev} = $rc->{"FRU.$f0.PCBRev"};
           }
         }

     } elsif ($d->{type} eq "6020") {
         require Agent::6020;
         my $rc = Agent::6020->getWWN($d->{ip}, undef, $TO, 1);
         my $frus = $d->{frus};
         foreach my $f0 (keys %$frus) {
             if ($rc->{"FRU.$f0.fruRevision"}) {
               $frus->{$f0}{revision}    = $rc->{"FRU.$f0.fruRevision"};
             }
             if ($rc->{"FRU.$f0.fruLoopVersion"}) {
               $frus->{$f0}{loopVersion} = $rc->{"FRU.$f0.fruLoopVersion"};
             }
             if ($rc->{"FRU.$f0.fruCtlrVersion"}) {
               $frus->{$f0}{ctlrVersion} = $rc->{"FRU.$f0.fruCtlrVersion"};
             }
         }
     }
  }
  $inv->writeInventory(undef, $HTML, 1);
  return 0;
}

sub read_versions {
  my($class) = @_;

  my $FIREWALL =  "/opt/SUNWsespfw/bin/get_version";
  my $NTC_V    =  "/opt/SUNWsespnc/bin/get_version";
  my($ntc_version, $fire_version);

  if (-x $FIREWALL) {
     $fire_version = `$FIREWALL`; chomp($fire_version);
     $fire_version =~ s/"//g;
  }
  if (-x $NTC_V) {
     $ntc_version  = `$NTC_V`;    chomp($ntc_version);
  }
  return ($ntc_version, $fire_version);
}



sub readMaserati {
  my($class, $short, $PREFIX, $trace, $HTML, $TO, $MODEL, $FILE) = @_;
  my(%T, $trace_out);
  my $devcnt   = 1;
  my $golden = [];
  my $xml;
  $PREFIX = "192.168" if (!$PREFIX);
  my $lines = Inventory->readHostLines();
  my $time_a = Util->get_today();

  if($FILE) {
    open(OO, ">/tmp/inventory_trace");
  }

  foreach my $l (@$lines) {
    chop($l);
    last if ($l eq "#DONE");
    next if (substr($l,0,1) eq "#");
    my ($ipno, $ip, $rest) = split(/\s+/, $l);
    next if (!$ipno);
    next if (substr($ipno,0,length($PREFIX) ) ne $PREFIX);
  
    my @X = split(/\./, $ipno);
    my $no = $X[3];
    my $version;
    if(!$FILE) {
      print "<br>" if ($HTML);
      print "$ip:\n";
    } else {
      print OO "<br>" if ($HTML);
      print OO "$ip:\n";
    }

    if ($X[2] == 0 && $no == 2) {  # sp
       my $key = "sp:" . System->hostid();
       my($build, $assembled) = System->read_release();
       my $hostinfo = System->hostinfo();
       my $model = System->model();

       my ($ntc_version, $fire_version) = $class->read_versions();

       push(@$golden, bless({
            type => "sp", class => "server.sp",
            ip   => $ipno,
            ipno => $ipno,
            name => $ip,
            key  => $key,
            wwn  => $key,
            hostinfo => $hostinfo,
	    time_added => $time_a,
            sysRevision => $build,
            frus  => { $ip => {
                         vendor   => "SUN",
                         serialNo => $key,
                         model    => $model,
                         revision => $build, 
                        assembled => $assembled, 
                              },
                       "$ip-ntc" => {
                         vendor   => "Lantronix",
                         serialNo => "spcomp1",
                          model   => "scs400",
                         revision => $ntc_version,
                              },
                       "$ip-firewall" => {
                         vendor   => "NetGear",
                         serialNo => "spcomp2",
                          model   => "rp114",
                         revision => $fire_version,
                              },
          
                      }
             }, 'Inv_dev') );
       my $o = "  -> found sp ($ipno) \n";
       $trace_out .= $o; 
       if(!$FILE) {
	 print $o ;
       } else {
	 print OO $o;
       }

    } elsif ($no == 10 ) { # PSX=1000
         if (!&ping($ipno)) {
             my $o = "  -> Warning: cannot ping $ipno \n";
             $o .= "     Device is not responding or not present in this configuration\n" ;
             $trace_out .= $o;
             if(!$FILE) {
	       print $o if ($trace);
	     } else {
	       print OO $o if ($trace);
	     }

             next;
         }

         $T{ve_cnt}++;
	 require Agent::DSP;
         my $rc  = Agent::DSP->getWWN($ipno, undef, $TO, 1);
         my $wwn = $rc->{wwn};
         if ($rc->{key}) {
             my $warn = &check_dsp($rc, "dsp", \$trace_out, $golden, 
                          $short, \%T, $ip, $ipno,  $trace, $rc->{userLabel});
             $T{warn} += $warn;

          } else {
             my $o = "  -> Error: cannot access DSP at $ip/$ipno $rc->{error} (remove password if present)\n";
             $trace_out .= $o; 
	     if(!$FILE) {
	       print $o;
	     } else {
	       print OO $o;
	     }
             $T{err}++ if($MODEL ne "6320");
	     next;
          }
  
    } elsif ($no >= 40 && $no <= 65) { # T4  CC
       if (&ping($ipno)) {
          my $rc = Agent::6020->getWWN($ipno, undef, $TO, 1);
	  if($rc->{err}){
	    if(!$FILE) {
	      print "ERROR on $ipno: $rc->{err}\n";
	    } else {
	      print OO "ERROR on $ipno: $rc->{err}\n";
	    }
	    $trace_out .= $rc->{err};
	  }else{
             my $warn = &check_t3($rc, "6020", \$trace_out, $golden, $short, \%T,
                                  $ip, $ipno, $trace, "Array");
             $T{warn} += $warn;
	  }
  
       } else {
          my $o = "  -> Warning: cannot ping $ipno \n";
          $o .= "     Device is not responding or not present in this configuration\n";
          $trace_out .= $o; 
	  if(!$FILE) {
	    print $o if ($trace);
	  } else {
	    print OO $o if ($trace);
	  }
       }
           
    } elsif ($no >= 300 && $no <= 33) { # switch
       if (&ping($ipno)) {
          my($wwn, $type, $ports, $rev) = &findSwitch($ipno);
          if (!$wwn) {
             my $o =  "  -> Error: cannot find the wwn of $ipno \n";
             $trace_out .= $o; 
	     if(!$FILE) {
	       print $o;
	     } else {
	       print OO $o;
	     }
             $T{err}++;
          } else {
              if (!$T{sw_ports}) {
                $T{sw_ports} = $ports;
                if ($T{sw_ports} != 16 && $T{sw_ports} != 8) {
		  if(!$FILE) {
                    print "  -> switch $ipno, invalid # ports: $T{sw_ports}\n";
		  } else {
		    print OO  "  -> switch $ipno, invalid # ports: $T{sw_ports}\n";
		  }
		  $T{err}++;
                }
              }
              $T{report_sw} .= "$ip, ";
              $T{sw_cnt}++;
              push(@$golden, bless({
                    type => $type, class => "switch.$type",
                    ip   => $ipno,
                    ipno => $ipno,
                    name => $ip,
                    key  => $wwn,
                    wwn  => $wwn,
                    ports => $T{sw_ports},
		    time_added => $time_a,
                    frus  => { $ip => {
                                 vendor   => "SUN",
                                 serialNo => $wwn,
                                 model    => "SUN-$type",
                                 revision => $rev, 
                                      }}}, 'Inv_dev') );
              my $o = "  -> found $type ($ipno / $wwn) \n";
              $trace_out .= $o; 
	      if(!$FILE) {
		print $o;
	      } else {
		print OO $o;
	      }
         }
  
       } else {
          my $o = "  -> Warning: cannot ping $ipno \n";
          $o .= "     Device is not responding or not present in this configuration\n";
          $trace_out .= $o; 
	  if(!$FILE) {
	    print $o if ($trace);
	  } else {
	    print OO $o if ($trace);
	  }
       }
     }
   }
   my $date = Util->get_today();
   my $date2 = `date`;
   chop($date2);

   my $INV = { created => $date, 
           created2 => $date2, 
           solution => "se2",
              stats => \%T,
           devices  => $golden,
          };

   if(!$FILE) {
     close(OO);
   }

   bless($INV, 'Inventory');
   return ($trace_out, $INV);
}




sub validateMaserati {
  my($inv, $MODEL, $trace) = @_;
  my ($prefix, $suffix, $trace_out, $model);

  my $T = $inv->{stats};

  if ($MODEL eq "6320" && $T->{sve_cnt} > 0) {
    my $o = "  -> Error: Found $T->{sve_cnt} ve, but model is $MODEL!\n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }
  
  if (($MODEL eq "6920" && $T->{sve_cnt} != 1) ||
      ($MODEL eq "6970" && $T->{sve_cnt} != 1)) { 
    my $o = "  -> Error: Wrong number of DSP($T->{sve_cnt}) found for $MODEL! \n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }
  if ($T->{t3_cnt} == 0) {
    my $o = "  -> Warning: No Storage Array found! \n";
    $trace_out .= $o; print $o;
    #$T->{err}++;
  }
  
  if ($T->{sw_ports} == 16 && $MODEL ne "6920") {
    my $o = "  -> Error: Model $MODEL need 8 port switches! \n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }
  
  if ($T->{sw_ports} == 8 && index("6320,6970", $MODEL) >= 0) {
    my $o = "  -> Error: Model $MODEL need 16 port switches! \n";
    $trace_out .= $o; print $o;
    $T->{err}++;
  }

  my $sl;
  if ($T->{sve_cnt} == 0) {
    $model = "6320";

  } elsif ($T->{sve_cnt} == 1) {
    $model = "6920";
  }
    
  if (0 && ($MODEL && $MODEL ne $model)) {
     my $o = "ERRORS: Model proposed ($MODEL) is different than discovered model ($model)\n";
     $trace_out .= $o; print $o;
     $T->{err}++;
  }
  $inv->{model} = $model;
  $T->{sw_cnt} += 0;
  $T->{sve_cnt} += 0;

  my $w_info = "|Warn(s) : $T->{warn}\n" if ($T->{warn});

  my $summary =<<EOF;

=====================================
|     Configuration Summary         |
-------------------------------------
|  Model : $model, Requested = $MODEL
|  Arrays: $T->{t3_cnt}
|          $T->{report_t3}
EOF
  if ($T->{sw_cnt}) {
    $summary .=<<EOF;
|  Switch: $T->{sw_cnt}, ports=$T->{sw_ports}
|          $T->{report_sw}
EOF
  }
  if ($T->{sve_cnt}) {
    $summary .=<<EOF;
|  DSPs  : $T->{sve_cnt}
|          $T->{report_sve}
EOF
  }
  $summary .=<<EOF;
| $w_info
=====================================

EOF

  return ($T->{err}, $trace_out, $summary);
}


# type, wwn, #ports, revision


# returns ($wwn , $type, $ports, $rev)

sub findSwitch {
  my($ip) = @_;
  my($wwn, $rev, $ports);
  my $type = "switch";

  my $DIR = System->get_home() ;
  my @lines = `$DIR/bin/sanbox version $ip`;
  foreach my $l (@lines) {
    if ($l =~ /WWN:\s+([0-9a-f]+)/) {
      $wwn = $1;
    } elsif ($l =~ /HW:\s+(.*)/) {
      $rev = $1;
    }
  }
  
  my @L = `$DIR/bin/sanbox chassis_status $ip`;

  foreach my $l (@L) {
    if ($l =~ /Ports:\s+(\d+)/) {
       $ports = $1;
    } 
  }

  @L = `$DIR/bin/sanbox get_zone $ip sl all`;
  if ("@L" !~ /Port: \d/) {
     $type = 'switch2';
  }

  return ($wwn, $type, $ports, $rev);
}

sub ping {
  my($ip) = @_;

  open(PING, "-|") or exec "/usr/sbin/ping", $ip, 3;  # TAINT
  my $ans = <PING>; close(PING);
  if ($ans =~ /is alive/) {
     return 1;
  } else {
     return 0;
  }
}

package Inv_dev;


sub frus {
   my($dev) = @_;
   return $dev->{frus};
}

sub info {
   my($dev, $val) = @_;
   if (exists $dev->{$val}) {
      return $dev->{$val};
   }
   return undef;
}

sub serialString {
  my($dev, $fru) = @_;

  if (index("t3,6120,6020,", $dev->{type}) >= 0) {
     return "$fru->{vendor} / $fru->{model} / $fru->{serialNo}";
  } elsif ($dev->{type} eq "dsp") {
     my $v = "SUN" if ($fru->{partNumber});
     return "$v / $fru->{partNumber} / $fru->{serialNumber}";
  } elsif ($dev->{type} eq "sp") {
     return "$fru->{vendor} / $fru->{model} / $fru->{serialNo}";
  } 
}

sub revisionString {
  my($dev, $fru) = @_;

  if (index("6020,6120" ,$dev->{type}) >= 0) {
     my $rev = "$fru->{ctrlVersion}$fru->{loopVersion}";
     $rev .= "/ " if ($rev);
     $rev .= $fru->{revision};
     return $rev;
  } elsif ($dev->{type} eq "dsp") {
     return "$fru->{hWRev} / $fru->{pCBRev}";

  } elsif ($dev->{type} eq "sp") {
     return $fru->{revision};
  }
}

     


1;
