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

use Util;
use AutoForm;
use strict;
use Tasks;
use Cache;
use Html::List;
use System;
use Scheduler;
use Client;
use Process;

use vars qw ($TT);
$TT = "ST";

#
# DELETE A JOB
# Client::ProcMgr::delete&id=$pid&type=diag|process..
# id    = host:prefix:pid
# prefix= ST
#
sub delete {
  my($q) = @_;
  my $type = $q->{type}; # diag or process...
  my $D1 = System->get_home() . "/DATA/Proc";
  my $real_host;

  print Client->http_OK();
  if ($type eq "diag" || index($q->{id}, ":ST:") > 0) {
     my($host, $prefix, $pid) = split(/\:/, $q->{id});    
     Scheduler->delete($prefix, $pid, $host);

  } elsif(  ($q->{id} =~ /(.*):(inband)/) || 
            ($q->{id} =~ /(.*):(deviceIP)/) || 
	    ($q->{id} =~ /(.*):(subnet)/) ){
     my $process = $2;
     $real_host = $q->{host};
     if($q->{host} ne "local"){
        # Find right host
        my ($renv, $devices, $hosts, $notifs, $Config) = PDM::ConfigFile->read();
        foreach my $h (@$hosts) {
           if (lc($h->{hostname}) eq lc($q->{host})) {
              $real_host = $h->{hostname};
	      last;
           }
	   # try short name as well
	   my $ix = index($h->{hostname}, ".");
           if($ix > 0){
              my $short = substr($h->{hostname}, 0, $ix);
              if (lc($short) eq lc($q->{host})) {
                 $real_host = $h->{hostname};
		 last;
	      }
           }
        }
     }

     my $D2 = System->get_home() . "/DATA/Discover/$process.$real_host";
     unlink $D2;
  }else {
     my($host, $pid) = split(/\:/, $q->{id});    
     Process->delete($host, $pid);

  }
}

#
# Delete an archived job
#
sub deleteArchive {
  my($q) = @_;
  my $type = $q->{type}; # diag or process...

  print Client->http_OK();

  if ($type eq "diag" || index($q->{id}, ":ST:") > 0) {
    my($host, $prefix, $pid) = split(/\:/, $q->{id}, 3);    
    chop($pid);
    my $name = $prefix."_".$pid;
    my $dir = System->get_home() . "/DATA/ProcArchive/$host";
    unlink "$dir/I_$name";
    unlink "$dir/O_$name";
    unlink "$dir/P_$name";
    print "$dir/I_$name";
    print "$dir/O_$name";
    print "$dir/P_$name";
  } else {
     my($host, $pid) = split(/\:/, $q->{id});    
     Process->delete($host, $pid, 1);
  }
}

# ARCHIVE A JOB
# id    = host:prefix:pid
# prefix= ST

sub archive {
  my($q) = @_;
  my $type = $q->{type}; # diag or process...
  my $D1 = System->get_home() . "/DATA/Proc";

  print Client->http_OK();

  if ($type eq "diag" || index($q->{id}, ":ST:") > 0) {
     my($host, $prefix, $pid) = split(/\:/, $q->{id});    
     Scheduler->archive($prefix, $pid, $host);

  } else {
     my($host, $pid) = split(/\:/, $q->{id});    
     Process->archive($host, $pid);
  }

}

#
# JOB DETAILS
# Client::ProcMgr::details&id=$pid&type=diag|process..
#
sub details {
  my($q) = @_;
  my $type = $q->{type}; # diag or process...
  my $renv = System->get_renv();
  my $D1 = System->get_home() . "/DATA/Proc";

  print Client->http_OK();

  if ($type eq "diag" || index($q->{id}, ":ST:") > 0) {
      my($hostname, $prefix, $pid) = split(/\:/, $q->{id});    
      next if (!-d "$D1/$hostname");
      my $list = Scheduler->processList($prefix,$hostname);
      foreach my $l (@$list) {
        # test if the pid of the process matches the id passed in
        if ($pid == $l->{pid}) {
          my $info    = $l->{info};
          my $options = Util->ltrim($l->{opts});
          $options = substr($options,2) if (substr($options,0,2)  eq "-o");
          $options =~ s/\|/, /g;
          my $INFO;
          foreach my $el (keys %$info) {
            my $val = $info->{$el};
            $INFO .= "    <" . uc($el) . ">$val</" . uc($el) . ">\n";
          }

          # get the details info (similar to Diag::status)
          # add these to the XML output
          my ($pinfo, $pro, $out, $err) = Scheduler->read($TT, $hostname, $pid);
          my $error;
          my $output;
          my($x, $y);
          for ($x=0; $x <= $#$err; $x++) {
            #print "error.$x.value\t$err->[$x]";
            $error = $error."error.$x.value\t$err->[$x]";
          }
          for ($x=0; $x <= $#$out; $x++) {
            my $rc = $out->[$x]{rc}; chomp($rc);
            #print "$out->[$x]{output}\n";
            $output = $output."$out->[$x]{output}\n";
          }
          my $status = &_status($l);
          # remove any <tag> from the ouput otherwise parsing this XML stream fails
#          $output =~ s/<(.*)>/$1/g;
			 $output = Client->xmlEncode($output);

          print <<EOF;
<DETAILS>
  <ID>$q->{id}</ID>
  <HOST>$hostname</HOST>
  <STATUS>$status</STATUS>
  <OPTIONS>options</OPTIONS>
  <START_DATE>$l->{start_date}</START_DATE>
  <END_DATE>$l->{end_date}</END_DATE>
  <PID>$l->{pid}</PID>
  <ERROR>$error</ERROR>
  <OUTPUT>$output</OUTPUT>
  <INFO>
$INFO  </INFO>
</DETAILS>
EOF
       }
    }
  } else {  # Process
     require Process;
     my($host, $id) = split(/\:/, $q->{id});
     $host = "" if ($host eq $renv->{hostname});

     # this case will happen at discovery job
     $host = "" if ($host eq "local");

     my $l= Process->details($host, $id);
     my $status = $l->{status};
     my $ix = index($status, "/");
     my $data   = Process->read($host, $id);
     my $trace  = Process->trace($host, $id);
     my $output = Process->readOut($host, $id);
     $trace =~ s/[<>]/ /g;
     if ($trace eq "" && $output ne "") {
       $trace = $trace.$output; 
     }

     my $INFO;
     if (ref($data) eq "HASH") {
        #$INFO = "<DATA>\n" . &parse_hash($data). "</DATA>";
     }
       
     $status = Util->rtrim(substr($status,0,$ix)) if ($ix > 0);

        print <<EOF;
<DETAILS>
  <ID>$q->{id}</ID>
  <HOST>$host</HOST>
  <STATUS>$status</STATUS>
  <OPTIONS>$l->{status}</OPTIONS>
  <START_DATE>$l->{start}</START_DATE>
  <END_DATE>$l->{end}</END_DATE>
  <PID>$l->{pid}</PID>
  <INFO>
     <DATA>$INFO</DATA>
     <TRACE>$trace
     </TRACE>
  </INFO>
</DETAILS>
EOF
   }
}

#
#
#
sub detailsArchive {
  my($q) = @_;
  my $type = $q->{type}; # diag or process...
  my $renv = System->get_renv();

  print Client->http_OK();

  if ($type eq "diag" || index($q->{id}, ":ST:") > 0) {
    my($host, $prefix, $pid) = split(/\:/, $q->{id}, 3);    

    my ($info, $pro, $out, $err) = Scheduler->read($TT, $host, $pid, {archive => 1});
    my $status = &_status($info);
    my $error;
    my $output;

    my $x;
    for ($x=0; $x <= $#$err; $x++) {
      $error = $error."error.$x.value\t$err->[$x]";
    }
    for ($x=0; $x <= $#$out; $x++) {
      my $rc = $out->[$x]{rc}; chomp($rc);
      $output = $output."$out->[$x]{output}\n";
    }
    $output =~ s/<(.*)>/$1/g;

    # also fill up the INFO DATA section with the output
    # to be able to use same structure as processes.

    print "<DETAILS>\n";
    print "  <ID>$q->{id}</ID>\n";
    print "  <HOST>$host</HOST>\n";
    print "  <STATUS>$status</STATUS>\n";
    print "  <START_DATE>$info->{start_date}</START_DATE>\n";
    print "  <END_DATE>$info->{end_date}</END_DATE>\n";
    print "  <PID>$info->{pid}</PID>\n";
    print "  <ERROR>$error</ERROR>\n";
    print "  <OUTPUT>$output</OUTPUT>\n";
    print "  <INFO><DATA>$output</DATA></INFO>\n";
    print "</DETAILS>\n";
  } else {
     require Process;
     my($host, $id) = split(/\:/, $q->{id});
     $host = "" if ($host eq $renv->{hostname});

     # this case will happen at discovery job
     $host = "" if ($host eq "local");

     my $l= Process->details($host, $id, undef, 1);
     my $status = $l->{status};
     my $ix = index($status, "/");
     my $data   = Process->read($host, $id, 1);
     my $trace  = Process->trace($host, $id, 1);
     my $output = Process->readOut($host, $id, 1);
     $trace =~ s/[<>]/ /g;
     if ($trace eq "" && $output ne "") {
       $trace = $trace.$output;
     }

     my $INFO;
     if (ref($data) eq "HASH") {
        #$INFO = "<DATA>\n" . &parse_hash($data). "</DATA>";
     }
       
     $status = Util->rtrim(substr($status,0,$ix)) if ($ix > 0);

        print <<EOF;
<DETAILS>
  <ID>$q->{id}</ID>
  <HOST>$host</HOST>
  <STATUS>$status</STATUS>
  <OPTIONS>$l->{status}</OPTIONS>
  <START_DATE>$l->{start}</START_DATE>
  <END_DATE>$l->{end}</END_DATE>
  <PID>$l->{pid}</PID>
  <INFO>
     <DATA>$INFO</DATA>
     <TRACE>$trace
     </TRACE>
  </INFO>
</DETAILS>
EOF
  }
}

sub parse_hash {
  my($data) = @_;
  my $val;

  foreach my $e (keys %$data) {
     if ($e eq "HASH") {
        $val .= &parse_hash($data->{$e});
     } else {
        $val .= "<$e>$data->{$e}</$e>\n";
     }
  }
}

#
# LIST ALL CURRENT PROCESSES 
#
sub list {
  my($q) = @_;
  my( $devs, $hosts,$notifs, $command, $opts, $sel,$local );
  my $renv = System->get_renv();
  my($out, $tag);
  $q->{prefix}  = "StorTools" if (!$q->{prefix});
  my $prefix = uc(substr($q->{prefix},0,2)) || "ST";
  print Client->http_OK();

  my $PLIST = $q->{PLIST}; # process _list

  my $MODE = $q->{MODE};

  my $cnt = 0;
  my $running;
  my(@DATA);
  my $D1 = System->get_home() . "/DATA/Proc";
  opendir(O, $D1);
  my @hd = readdir(O); closedir(O);
  print "<PROCESSES>\n";

  foreach my $hostname (@hd) {
     next if (!-d "$D1/$hostname");
     next if (index($hostname, ":") >= 0);
     my $list = Scheduler->processList($prefix,$hostname, 
                             {status => $MODE, plist => $PLIST} );
     foreach my $l (@$list) {
        my $sh   = Util->shortHostname($l->{host});
        my $host = $l->{host};
        my $cmd  = $l->{command};
        my $pid  = $l->{pid};
        my $prefix = $l->{task_type};
        my $pid0  = sprintf("%6.6d", $l->{pid});
        my $status = &_status($l);
        my $start = $l->{start_date};
        my $end   = $l->{end_date};

        $end = substr($end,11) if (substr($start,0,10) eq substr($start,0,10));
        print <<EOF;
   <PROCESS>
     <ID>$host:$prefix:$pid</ID>
     <HOST>$host</HOST>
     <PID>$pid</PID>
     <TYPE>process.diag</TYPE>
     <NAME>$cmd</NAME>
     <START>$start</START>
     <END>$end</END>
     <STATUS>$status</STATUS>
   </PROCESS>
EOF

     }
  }
  require Process;
  my $L2 = Process->list();

  foreach my $p (@$L2) {
    next if($p->{id} eq "subnet");
    next if($p->{id} eq "deviceIP");
    next if($p->{id} eq "inband");
    next if($p->{id} =~ /Install_Verify/);

    # status is of the form: 'Done / Wed May 12 11:39:12 MDT 2004'
    # extract the part before the delimiter.
    my($status) = split(/ \//, $p->{status});
    my $host = $p->{host} || $renv->{hostname};
     print <<EOF;
  <PROCESS>
    <ID>$host:$p->{id}</ID>
    <HOST>$host</HOST>
    <PID>$p->{pid}</PID>
    <TYPE>process.$p->{id}</TYPE>
    <NAME></NAME>
    <START>$p->{start}</START>
    <END>$p->{end}</END>
    <STATUS>$status</STATUS>
  </PROCESS>
EOF
  }

  # ADD REMOTE DISCOVERY
  require Discover;
  my $disco = Discover->stats(1);
  foreach my $el (sort keys %$disco) {
     my($method, $host) = split(/\./, $el);
     my $p = $disco->{$el};
     print <<EOF;
  <PROCESS>
    <ID>$host:$method</ID>
    <HOST>$host</HOST>
    <PID>$method</PID>
    <TYPE>discover.$method</TYPE>
    <NAME></NAME>
    <START>$p->{start_date}</START>
    <END>$p->{end_date}</END>
    <STATUS>$p->{status}</STATUS>
  </PROCESS>
EOF
  }
    
  print "</PROCESSES>\n";


}

#
# list archived processes.
#
sub listArchive {
  my($q) = @_;
  my( $devs, $hosts,$notifs, $command, $opts, $sel,$local );
  my $renv = System->get_renv();
  my($out, $tag);
  $q->{prefix}  = "StorTools" if (!$q->{prefix});
  my $prefix = uc(substr($q->{prefix},0,2)) || "ST";
  print Client->http_OK();

  my(@DATA, $x);

  my $PLIST = $q->{PLIST}; # process _list

  my $MODE = $q->{MODE};

  my $cnt = 0;
  my $running;
  my(@DATA);
  my $D1 = System->get_home() . "/DATA/ProcArchive";
  opendir(O, $D1);
  my @hd = readdir(O); closedir(O);
  print "<PROCESSES>\n";

  ##my $days = $q->{DAYS} || 10;
  my $AR = System->get_home() . "/DATA/ProcArchive";
  return if (!-d $AR);
  chdir $AR;
  ##my $com = "/usr/bin/find . -type f -name \"I_${prefix}_*\" -mtime -$days";
  my $com = "/usr/bin/find . -type f -name \"I_${prefix}_*\" ";
  my @L2;
  @L2 = `$com`;

  for ($x=0; $x <= $#L2; $x++) {
    my $f = substr($L2[$x],2);
    my($host,$name) = split(/\//, $f);
    my $info = Scheduler->readInfo($host, substr($name,2), {archive => 1});
    my $status = &_status($info);
    print "  <PROCESS>\n";
    print "    <ID>$info->{host}:$info->{task_type}:$info->{pid}</ID>\n";
    print "    <HOST>$info->{host}</HOST>\n";
    print "    <PID>$info->{pid}</PID>\n";
    print "    <TYPE>process.diag</TYPE>\n";
    print "    <NAME>$info->{command}</NAME>\n";
    print "    <START>$info->{start_date}</START>\n";
    print "    <END>$info->{end_date}</END>\n";
    print "    <STATUS>$status</STATUS>\n";
    print "  </PROCESS>\n";
  }

  require Process;
  my $L2 = Process->list(1);
  foreach my $p (@$L2) {
    # status is of the form: 'Done / Wed May 12 11:39:12 MDT 2004'
    # extract the part before the delimiter.
    my($status) = split(/ \//, $p->{status});
    my $host = $p->{host} || $renv->{hostname};

    print "  <PROCESS>\n";
    print "    <ID>$host:$p->{id}</ID>\n";
    print "    <HOST>$host</HOST>\n";
    print "    <PID>$p->{pid}</PID>\n";
    print "    <TYPE>process.$p->{id}</TYPE>\n";
    print "    <NAME></NAME>\n";
    print "    <START>$p->{start}</START>\n";
    print "    <END>$p->{end}</END>\n";
    print "    <STATUS>$status</STATUS>\n";
    print "  </PROCESS>\n";
  }
  print "</PROCESSES>\n";
}

sub _status {
  my($p) = @_;

  if ($p->{status} eq "O") {
    return "Running";
  } elsif ($p->{status} eq "OQ")  {
    return "Waiting..";

  } elsif ($p->{rc} =~ /143/)  {
    return "Done:ABORTED";

  } elsif ( ( $p->{rc} >> 8 ) =~ /143/)  {
    return "Done:ABORTED";
  } elsif ($p->{rc} =~ /140/)  {
    return "Done:ISOLATED";

  } elsif ( ( $p->{rc} >> 8 ) =~ /140/)  {
    return "Done:ISOLATED";


  } elsif ($p->{rc} =~ /35072/)  {
    return "Done:ABORTED";

  }elsif ($p->{rc} =~ /999/)  {
    return "Done:SYNC";

  }
  elsif ($p->{rc} !~ /^[0\-,]+$/ ) {
    return "Done:ERROR";
  } else {
    return "Done:OK";
  }
}

#
# Client::ProcMgr::isAgentRunning&hostID=1.2.3.4
#
sub isAgentRunning {
  my($q) = @_;
  my $ID = "rasagent";

  my $IPS    = System->ifconfigs();
  my $ip = "";
  foreach my $i (@$IPS) {
    $ip .= " $i->[1]," if ($i->[1] ne "127.0.0.1");
  }
  chop($ip) if ($ip);

  print Client->http_OK();

  if(!$q->{hostID} || $ip eq $q->{hostID}) {
    my $process = Util->findProcessByName("/rasagent");
    if ($process) {
      print Client->errno(402); # agent already running.
      return;
    }
  }
  print "no";
}

#
#  Client::ProcMgr::runAgent&hostID=1.2.3.4&force=1&audit=1&nomax=1
#
sub runAgent {
  my($q) = @_;
  my $ID = "rasagent";

  my $trace = System->get_home() . "/DATA/tmp/$ID" . "_trace";

  my $force = "-f" if ($q->{force});
  my $audit = "-A" if ($q->{audit});
  my $nomax = "-M" if ($q->{nomax});

# check if it is a local host

  my $IPS    = System->ifconfigs(); 
  my $ip = "";
  foreach my $i (@$IPS) {
     $ip .= " $i->[1]," if ($i->[1] ne "127.0.0.1");
  }
  chop($ip) if ($ip);
  
  print Client->http_OK();

  if(!$q->{hostID} || $ip eq $q->{hostID}) {
    my $process = Util->findProcessByName("/rasagent");
    if ($process) {
      print Client->errno(402); # agent already running.
      return;
    }

    system("/opt/SUNWstade/bin/rasagent -d2 -r -a $force $audit $nomax -P > $trace 2>&1&");
    sleep(2);
    my $date = Util->get_today();
    print "<RUNAGENT>$date</RUNAGENT>\n";
  } else {

    if (!Util->ping($q->{hostID}, 5)) {
      print Client->errno(403, [$q->{hostID}]);
      return;
    }
  
    Util::Http->deleteFile($q->{hostID}, "$trace");

    my($err, $rc) = Util::Http->runshell($q->{hostID}, "/bin/rasagent -d2 -r $force $audit $nomax>$trace 2>&1");
    sleep(2);

    my $date = Util->get_today();
    print "<RUNAGENT>$date</RUNAGENT>\n";
  }
}

sub getRunAgentResult {
  my($q) = @_;
  my ($err, $rc);
  my $out;

  print Client->http_OK();
 
 
  my $ID = "rasagent";
  my $trace = System->get_home() . "/DATA/tmp/$ID" . "_trace";

  # check if it is a local host
  my $IPS    = System->ifconfigs(); 
  my $ip = "";
  foreach my $i (@$IPS) {
     $ip .= " $i->[1]," if ($i->[1] ne "127.0.0.1");
  }
  chop($ip) if ($ip);

  if(!$q->{hostID} || $ip eq $q->{hostID}) { 
    open(O, $trace);
    my @lines = <O>; 
    close(O);
    $rc = "@lines";
  } else {
    ($err, $rc) = Util::Http->readFile($q->{hostID}, "/tmp/$ID" . "_trace");
  }
  my $done;
  if ($err && $err !~ /unexpected EOF/) {
    $rc .= "Error trying to read DATA/tmp/run_agent$q->{PID}.out on $q->{hostID}: $err \n";
    # Ensure rc has remove pid
    $rc .= "REMOVE_PID";
  } 

  $out .= $rc;
  $out = Client->xmlEncode($out);

  print "<RUNAGENT>$out</RUNAGENT>\n";
}

1;
