# $Id: Diagx.pm,v 1.28 2006/06/08 21:31:07 mckenney Exp $
# Copyright 2003,2004  Sun Microsystems, Inc., All Rights Reserved.
package Client::Diagx;

use Client;
use Debug;
use AutoForm;
use Scheduler;
use TO;
use Report;
use Diag;
use System;
use Java::JavaDiags;
use LockManager;
use strict;
use vars qw ($TT);
$TT = "ST";


use Data::Dumper;

# Return a list of diagnostic test options for either a device type or
# for a given device with options specific for the given device.
# key = "DeviceType:DeviceKey" for specific device
# type = device type for class of device.
# ACTIVE : if the devive is a host will check that the host has hbas
# before returning the list of diagnostics.
sub list {
  my($q) = @_;
  my $format   = "xml";
  my $key      = $q->{key};
  my $devType  = $q->{type};
  my $locale   = $q->{locale};
  my $type     = $devType;
  my $devKey;

  if ($key){
	 ($type, $devKey) = split(/\:/, $key);
  }


  my($comp, $tests, $dev, $x, $key0);
  my($renv, $devices, $hosts, $notifs) = PDM::ConfigFile->read();

  my($err,$af) = AutoForm->new("System/Tests", {noInfo => 1, locale => $locale});

  my $cnt=1;

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

  # Return test for a specific device.
  if ($key) {
     Debug->logLine("Client::Diag::list for $key");

     my $to = TO->readExistingTopo("MERGE-MASTER") || TO->readExistingTopo();
     if (!$to) {
         print Client->error($format, 110, "No topology available!");
         return;
     }
     my($type, $k) = split(/\:/, $key);
     $dev = $to->nodeByName($key);
     if (!$dev) {
	print Client->error($format, 109, "Device $key not found in topology, ensure device is being monitored correctly. No Diags will be found until this is corrected.");
	return;
     }

     Debug->logLine("Client::Diag::list dev=$dev key=$key type=$type");

     # check if we have volumes?
     my $hasVolumes = 0;
     my $vols = $dev->volInfo();
     if (defined($vols)) {
       $hasVolumes = 1;
     }

     $comp = "e";
     if ($type eq "host") {
       $comp = "all";
     }

     $tests = Tasks->ST_getTestList($af, $type, $dev, $comp);
     if ($#$tests < 0) {
       # try locale fallback solution if non-en locale
       if($locale && $locale ne "en") {
	 ($err,$af) = AutoForm->new("System/Tests", {noInfo => 1});
	 $tests = Tasks->ST_getTestList($af, $type, $dev, $comp);
       }
     }

     if ($#$tests < 0) {
       my $jerror = Client::Diagx::jlist($type, $devKey, "DIAG_LIST", $locale);
       if ($jerror){
	 print Client->error("xml", 110, "No test available for $type $key");
       }
       return;
     }

     require Diag;
     print Client->http_OK();
     print Client->xmlTag("DIAG_LIST");

     Client::Diagx::jlist($type, $devKey, undef, $locale);

     foreach my $t (@$tests) {
       my $testName = $t->{info}{sectionName};

       # skip it if inband test but no volumes.
       my $node = $t->{info}{node};
       next if (($node eq "v" || $node eq "d") && $hasVolumes == 0);

       my $c = $af->commandByName($testName);
       my($form_err, $form_data) = Diag->validation($c, $testName, $to, $dev, {}, "preForm");
       # if we are in storade mode, keep parameters as is
       if ($mode ne "storade") {
         $form_data->{'#PASSES'} = 1;
       }
       my($cn, $reg_select, $all, $all_reg, $node, $multiple) =
	 Diag->register_list($type, $af, $t->sectionName() , $dev, "e", {mode => 'list'});
       &printit($af, $t, $cnt, $reg_select, $form_data, $form_err);
       $cnt++;
     }
     print Client->xmlEndTag("DIAG_LIST");
     return;
  }

  Debug->logLine("Client::Diag::list for $devType");

  $Data::Dumper::Indent = 1;

  # BY DEFAULT, SHOW RACK-LEVEL TESTS
  my $mgmtLevel = $q->{mgmtLevel};
  $mgmtLevel = "DS" if (!$devType && !$mgmtLevel);

  my $foundTest = 0;
  foreach my $com ($af->commandList()) {
     my $c = $af->commandByName($com);
     my $info = $c->info();
     next if ($devType && $info->{devType} ne $devType);
     next if ($mgmtLevel eq "DS" && $info->{devType} ne $renv->{solution});
	  if (!$foundTest){
		 $foundTest++;
		 print Client->http_OK();
		 print Client->xmlTag("DIAG_LIST");
	  }
     &printit($af, $c, $cnt);
     $cnt++;
  }

  if ($foundTest){
	 print Client->xmlEndTag("DIAG_LIST");
  }
  else {
	 print Client->error("xml", 110, "No test available for $devType $key");
  }
}

sub printit {
  my($af, $c, $cnt, $regs, $form_data, $form_err) = @_;
  my($x);
  my $info = $c->info();

  print Client->xmlTag("DIAG_TEST");

  # is there any warning to be displayed in addition of the parameters?
  print Client->xmlTag("TEST_PRE_WARNING");
  if (defined($form_err)) {
    print Client->xmlEncode($form_err);
  }
  print Client->xmlEndTag("TEST_PRE_WARNING");

  print Client->xmlTag("TEST_INFO");

  foreach my $v (sort keys %$info) {
    print Client->xmlVALUE($v, $info->{$v});
  }
  print Client->xmlEndTag("TEST_INFO");

  if ($regs) {
    $regs =~ s/\t/\|/g;
    print Client->xmlTag("TEST_OPT");
    print Client->xmlVALUE("desc", "Register");
    print Client->xmlVALUE("name", "Register");
    print Client->xmlVALUE("opt", "register");
    print Client->xmlVALUE("type", "select");
    print Client->xmlVALUE("values", $regs);
    print Client->xmlEndTag("TEST_OPT");
  }

  my $opts = $c->{opts};
  for ($x=0; $x <= $#$opts; $x++) {
    print Client->xmlTag("TEST_OPT");
    my $opt = $opts->[$x];
    foreach my $v (sort keys %$opt) {
      my $V = exists $form_data->{$opt->{$v}} ? $form_data->{$opt->{$v}} : $opt->{$v};
      print Client->xmlVALUE($v, $V);
    }
    print Client->xmlEndTag("TEST_OPT");
  }


  if ($info->{defaults}) {
    my $c = $af->commandByName("DEFAULTS");
    my $def_opts = $c->{opts};
    for ($x=0; $x <= $#$def_opts; $x++) {
      print Client->xmlTag("TEST_OPT");
      my $opt = $def_opts->[$x];
      foreach my $v (sort keys %$opt) {
	my $V = exists $form_data->{$opt->{$v}} ? $form_data->{$opt->{$v}} : $opt->{$v};
	print Client->xmlVALUE($v, $V);
      }
      print Client->xmlEndTag("TEST_OPT");
    }
  }

  print Client->xmlEndTag("DIAG_TEST");
}

# GO=Client::Diag::run&key=sve:sdasda&test=se_configcheck&opt_verbose=on&opt_register=port1:1:192..

sub run {
  my($q) = @_;
  my $format = $q->{format} || "xml";
  my $key = $q->{key};
  if (!$key) {
	 print Client->errno(211, [$key]);
	 return;
  }

  my($type, $k) = split(/\:/, $key);
  my $lease = LockManager->new();
  $lease->cleanLocks();
  my $lockInfo = $lease->read($k);
  if ($lockInfo){
	 print Client->errno(204, [$key]);
	 return;
  }

  my $jerror = Java::JavaDiags::run($q);
  if (!$jerror){
	 return;
  }

  my($comp, $tests, $dev, $x);
  my($renv, $devices, $hosts, $notifs) = PDM::ConfigFile->read();
  my $selected_test = $q->{test};
  my $host = $renv->{hostname};
  my $format = $q->{format} || "xml";
  $q->{register} = $q->{opt_register} if ($q->{opt_register});

  my $to = TO->readExistingTopo("MERGE-MASTER") || TO->readExistingTopo();
  $dev = $to->nodeByName($key);

  if (!$dev) {
    Debug->logLine("Client::Diag::run $key not found in topo!");
    print Client->error($format, 111, "Device $key not found in topo!");
    return;
  }

  my($af_err,$af) = AutoForm->new("System/Tests", {noInfo => 1});

  my $af_test = $af->commandByName($selected_test);

  my($valid_err, $run_err, $text, $pid, $test_command, $opts ) = 
         Diag->run($af, $host, $q, $af_test, $selected_test, $to, $dev, "$key:e", 1);  # quiet


  if ($valid_err) {
    Debug->logLine("Client::Diag::run Validation Error: $valid_err");
      print Client->error($format, 111,"Validation Error: $test_command: $valid_err");
      return;
  }
  if ($text) {
    Debug->logLine("Client::Diag::run Command: $text");
    print Client->http_OK();
    print Client->xmlTag("DIAG_RUN");
    print Client->xmlEncode($text);
    print Client->xmlEndTag("DIAG_RUN");
    return;
  }

  if ($run_err) {
    Debug->logLine("Client::Diag::run $test_command: $run_err");
    print Client->error($format, 111,"$test_command: $run_err");
    return;
  } else {
    print Client->http_OK();
    if ($q->{DIRECT}) {
      return $pid;
    } else {
      Debug->logLine("Client::Diag::run $key $pid");
      print Client->xmlTagOpen("DIAG_RUN");
      print Client->xmlAttrib("status", "OK");
      print Client->xmlAttrib("pid", $pid);
      print Client->xmlTagClose();
    }
  }
}

# returns status and report itself
sub status {
  my($q) = @_;
  my $format = $q->{format} || "xml";
  my($renv, $devices, $hosts, $notifs) = PDM::ConfigFile->read();
  my $selected_test = $q->{test};
  my $host = $renv->{hostname};
  my $pid  = $q->{pid};

  print Client->http_OK();
  print Client->xmlTagOpen("DIAG_STATUS");
  print Client->xmlAttrib("pid", $pid);
  print Client->xmlTagClose();

  my ($info, $pro, $out, $err) = Scheduler->read($TT, $host, $pid) ;

  use Data::Dumper();
  print Dumper($info);

  print Client->xmlTag("STATUS_INFO");
  foreach my $v (sort keys %$info) {
    if ($v eq "info" ){
      print Client->xmlTag("INFO_DETAILS");
      my $sub = $info->{$v};
      foreach my $v1 (sort keys %$sub) {
		  print Client->xmlVALUE($v1, $sub->{$v1});
      }
      print Client->xmlEndTag("INFO_DETAILS");
    }
	 else {
      my $sub = $info->{$v};
      print Client->xmlVALUE($v, $sub);
    }
  }
  print Client->xmlEndTag("STATUS_INFO");

  my($x, $y);
  for ($x=0; $x <= $#$err; $x++) {
    print Client->xmlTag("DIAG_ERROR");
    print Client->xmlEncode($err->[$x]);
    print Client->xmlEndTag("DIAG_ERROR");
  }

  for ($x=0; $x <= $#$out; $x++) {
    my $rc = $out->[$x]{rc}; chomp($rc);
    print Client->xmlTagOpen("DIAG_OUTPUT");
    print Client->xmlAttrib("rc", $rc);
    print Client->xmlAttrib("date",$out->[$x]{date});
    print "/>";
    print Client->xmlEncode($out->[$x]{output});
    print Client->xmlEndTag("DIAG_OUTPUT");
  }

  print Client->xmlEndTag("DIAG_STATUS");
}

# Abort a running test given a pid.
sub abort {
  my($q) = @_;
  my $format = $q->{format} || "xml";

  print Client->http_OK();
  print Client->xmlTagOpen("DIAG_ABORT");

  my($renv, $devices, $hosts, $notifs) = PDM::ConfigFile->read();
  my $host = $renv->{hostname};
  my $pid  = $q->{pid};
  my ($info, $pro, $out, $err) = Scheduler->read($TT, $host, $pid) ;
  my $done = Scheduler->kill($TT,$pid, $host , {child => 1, signal => 15});

  if (!$done) {
    print Client->xmlAttrib("status", "ERROR");
    print Client->xmlTagClose();
    print Client->xmlEncode($Scheduler::ERROR);
    print Client->xmlEndTag("DIAG_ABORT");
  } else {
    print Client->xmlAttrib("status", "OK");
    print Client->xmlTagClose();
  }
  Debug->logLine("Client::Diag::abort $pid $done $Scheduler::ERROR");
}



# List tests from the java framework.
sub jlist {
  my($type, $key, $header, $locale) = @_;

  my $reply = Java::JavaDiags::list($type, $key, $locale);
  if ($reply->{error}){
	  Debug->logLine
		 ("Client::Diagx::jlist error getting java tests for $type.");
	  return 110;
  }

  my $tests = $reply->{tests};
  if ($tests){
	 if ($header){
		print Client->http_OK();
		print "<$header>\n";
	 }
    my $index;
    for($index = 0; $index <= $#$tests; $index++) {
      my $test      = $tests->[$index];
      my @all =   split(/\n/, $test);
      foreach my $l (@all){
	if($l =~ /\<\/DIAG_TEST\>/){
           print "<TEST_OPT>\n";
           print " <VALUE ID='name'>Send Results to Email</VALUE>\n";
           print " <VALUE ID='opt'>#EMAIL</VALUE>\n";
           print " <VALUE ID='size'>25</VALUE>\n";
           print " <VALUE ID='type'>text</VALUE>\n";
           print " <VALUE ID='value'>X</VALUE>\n";
           print "</TEST_OPT>\n";
	   print "<TEST_OPT>\n";
	   print " <VALUE ID='name'>Number of passes</VALUE>\n";
	   print " <VALUE ID='opt'>#PASSES</VALUE>\n";
           print " <VALUE ID='type'>select</VALUE>\n";
	   print " <VALUE ID='values'>1|2|3|10|50|100|500|1000|2000|5000|999999=Forever</VALUE>\n";
           print " <VALUE ID='default'>1</VALUE>\n";
	   print "</TEST_OPT>\n";

	}
	print "$l\n";
      }
    }
	 if ($header){
		print "</$header>";
	 }
	 return 0;
  }
  else {
	 return 110;
  }
}


1;
