#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::monctrlcmds;
BEGIN
{
  $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl";

use xCAT::NodeRange;
use xCAT::Table;
use xCAT::MsgUtils;
use xCAT_monitoring::monitorctrl;
use xCAT::Utils;

my $callback;
1;



#-------------------------------------------------------------------------------
=head1  xCAT_plugin:monctrlcmds
=head2    Package Description
  xCAT monitoring control commands plugini module. This modules handles
  monitoring related commands.
=cut
#-------------------------------------------------------------------------------



#--------------------------------------------------------------------------------
=head3   handled_commands
      It returns a list of commands handled by this plugin.
    Arguments:
        none
    Returns:
        a list of commands.
=cut
#--------------------------------------------------------------------------------
sub handled_commands {
  return {
    monstart => "monctrlcmds",
    monstop => "monctrlcmds",
    monupdate => "monctrlcmds",
    monls => "monctrlcmds",
    monaddnode => "monctrlcmds",
    monrmnode => "monctrlcmds",
    moncfgmaster => "monctrlcmds",
  }
}

#-------------------------------------------------------
=head3  preprocess_request

  Check and setup for hierarchy 

=cut
#-------------------------------------------------------
sub preprocess_request
{
  my $req = shift;
  my $cb  = shift;
  my $command = $req->{command}->[0];
  if ($req->{_xcatdest}) { return [$req]; }    #exit if preprocessed

  my @requests=();

  if ($command ne "moncfgmaster") {
    my $reqcopy = {%$req};
    push @requests, $reqcopy;
  } else {
    if (! xCAT_monitoring::monitorctrl->shouldConfigMaster()) { 
      $req = {};
      return;
    }

    my $nodes = $req->{node};
    my $noderef=xCAT_monitoring::monitorctrl->getMonServer($nodes);

    #the identification of this node
    my @hostinfo=xCAT::Utils->determinehostname();
    my $isSV=xCAT::Utils->isServiceNode();
    %iphash=();
    foreach(@hostinfo) {$iphash{$_}=1;}
    if (!$isSV) { $iphash{'noservicenode'}=1;}

    foreach my $key (keys (%$noderef)) {
      my @key_a=split(',', $key);
      my $mon_nodes=$noderef->{$key};
      @nodes_to_add=();
      if ($mon_nodes) {
        foreach(@$mon_nodes) {
          my $node=$_->[0];
          push(@nodes_to_add, $node);
        }     
      }
      if ($iphash{$key_a[0]}) { #current node is the master for the nodes
        my $reqcopy = {%$req};
        $reqcopy->{node}=\@nodes_to_add;
        push @requests, $reqcopy;
      } else { #push the request to the monitoring server
        my $reqcopy = {%$req};
        $reqcopy->{node}=\@nodes_to_add;
        $reqcopy->{'_xcatdest'} = $key_a[0];
        push @requests, $reqcopy;
      }  
    }
  }
  return \@requests;
}


#--------------------------------------------------------------------------------
=head3   process_request
      It processes the monitoring control commands.
    Arguments:
      request -- a hash table which contains the command name.
      callback -- a callback pointer to return the response to.
      args -- a list of arguments that come with the command. 
    Returns:
        0 for success. The output is returned through the callback pointer.
        1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub process_request {
  use Getopt::Long;
  # options can be bundled up like -vV
  Getopt::Long::Configure("bundling") ;
  $Getopt::Long::ignorecase=0;
  
  my $request = shift;
  $callback = shift;
  my $command = $request->{command}->[0];
  my $args=$request->{arg};
  my $doreq = shift;

  if ($command eq "monstart") {
    my ($ret, $msg) = monstart($args, $callback, $doreq);
    if ($msg) {
      my %rsp=();
      $rsp->{dara}->[0]= $msg;
      $callback->($rsp);
    }
    return $ret;
  } 
  elsif ($command eq "monstop") {
    my ($ret, $msg) = monstop($args, $callback, $doreq);
    if ($msg) {
      my %rsp=();
      $rsp->{data}->[0]= $msg;
      $callback->($rsp);
    }
    return $ret;
  } 
  elsif ($command eq "monupdate") {
    xCAT_monitoring::monitorctrl::sendMonSignal();
  }
  elsif ($command eq "monls") {
    my ($ret, $msg) = monls($args, $callback);
    if ($msg) {
      my %rsp=();
      $rsp->{data}->[0]= $msg;
      $callback->($rsp);
    }
    return $ret;
  }
  elsif ($command eq "monaddnode") {
    my ($ret, $msg) = monaddnode($args, $callback);
    if ($msg) {
      my %rsp=();
      $rsp->{data}->[0]= $msg;
      $callback->($rsp);
    }
    return $ret;
  }
  elsif ($command eq "monrmnode") {
    my ($ret, $msg) = monrmnode($args, $callback);
    if ($msg) {
      my %rsp=();
      $rsp->{data}->[0]= $msg;
      $callback->($rsp);
    }
    return $ret;
  }
  elsif ($command eq "moncfgmaster") {
    my $nodes = $request->{node};
    if ($nodes) {
      my ($ret, $msg) = moncfgmaster($nodes, $callback);
      if ($msg) {
        my %rsp=();
        $rsp->{data}->[0]= $msg;
        $callback->($rsp);
      }
      return $ret;
    } else {
      my %rsp=();
      $rsp->{data}->[0]= "This command requires noderange.";
      $callback->($rsp);
      return 1;
    }
  }
  else {
    my %rsp=();
    $rsp->{data}->[0]= "unsupported command: $command.";
    $callback->($rsp);
    return 1;
  }
}

sub take_answer {
  my $resp = shift;
  $callback->($resp);
}


#--------------------------------------------------------------------------------
=head3   monstart
        This function registers the given monitoring plug-in to the 'monitoring' table.
        xCAT will invoke the monitoring plug-in to start the 3rd party software, which
        this plug-in connects to, to monitor the xCAT cluster. 
    Arguments:
      callback - the pointer to the callback function.
      args - The format of the args is:
        [-h|--help|-v|--version] or
        name [-n|--nodestatmon] [-s|--settings ...]        
        where
          name is the monitoring plug-in name. For example: rmcmon. 
              The specified plug-in will be registered and invoked 
              for monitoring the xCAT cluster.
          -n|--nodestatmon  indicates that this plug-in will be used for feeding the node liveness
              status to the xCAT nodelist table.  If not specified, the plug-in will not be used 
              for feeding node status to xCAT. 
          -s|--settings settings are used by the plug-in to customize it behavor.
    Returns:
        0 for success. The output is returned through the callback pointer.
        1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monstart {
  my $args=shift;
  my $callback=shift;
  my $doreq = shift;
  my $VERSION;
  my $HELP;

  if (xCAT::Utils->isServiceNode()) {
    my %rsp=();
    $rsp->{data}->[0]= "This command is not supported on a service node.";
    $callback->($rsp);
    return 0;
  }


  # subroutine to display the usage
  sub monstart_usage
  {
    my %rsp;
    $rsp->{data}->[0]= "Usage:";
    $rsp->{data}->[1]= "  monstart name [-n|--nodestatmon] [-s|--settings settings]";
    $rsp->{data}->[2]= "  monstart [-h|--help|-v|--version]";
    $rsp->{data}->[3]= "     name is the name of the monitoring plug-in module to be registered and invoked.";
    $rsp->{data}->[4]= "       Use 'monls -a' command to list all the monitoring plug-in names.";
    $rsp->{data}->[5]= "     settings is used by the monitoring plug-in to customize its behavior.";
    $rsp->{data}->[6]= "       Format: [key1=value1],[key2=value2]... ";
    $rsp->{data}->[7]= "       Please note that the square brackets are needed. ";
    $rsp->{data}->[7]= "       Use 'monls name -d' command to look for the possible settings for a plug-in.";
    $rsp->{data}->[8]= "  Example: monstart xcatmon -n -s [ping-interval=10]";
    $callback->($rsp);
  }
  
  @ARGV=@{$args};
  my $settings;

  # parse the options
  if(!GetOptions(
      'h|help'     => \$::HELP,
      'v|version'  => \$::VERSION,
      'n|nodestatmon'  => \$::NODESTATMON,
      's|settings=s'  => \$settings))
  {
    &monstart_usage;
    return;
  }

  # display the usage if -h or --help is specified
  if ($::HELP) { 
    &monstart_usage;
    return;
  }

  # display the version statement if -v or --verison is specified
  if ($::VERSION)
  {
    my %rsp;
    $rsp->{data}->[0]= "monstart version 1.0";
    $callback->($rsp);
    return;
  }

  #my @product_names;
  my $pname;
  if (@ARGV < 1)
  {
    &monstart_usage;
    return;
  }
  else {
    #@product_names=split(/,/, $ARGV[0]);
    $pname=$ARGV[0];
    $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
      if (!-e $file_name) {
        my %rsp;
        $rsp->{data}->[0]="File $file_name does not exist.";
        $callback->($rsp);
        return 1;
      }  else {
        #load the module in memory
        eval {require($file_name)};
        if ($@) {   
          my %rsp;
          $rsp->{data}->[0]="The file $file_name has compiling errors:\n$@\n";
          $callback->($rsp);
          return 1;  
        }      
      }
  }

  #my %ret = xCAT_monitoring::monitorctrl::startmonitoring(@product_names);
  
  #my %rsp;
  #$rsp->{data}->[0]= "starting @product_names";
  #my $i=1;
  #foreach (keys %ret) {
  #  my $ret_array=$ret{$_};
  #  $rsp->{data}->[$i++]= "$_: $ret_array->[1]";
  #}

  #my $nodestatmon=xCAT_monitoring::monitorctrl::nodeStatMonName();
  #if ($nodestatmon) {
  #  foreach (@product_names) {
  #    if ($_ eq $nodestatmon) { 
  #	my ($code, $msg)=xCAT_monitoring::monitorctrl::startNodeStatusMonitoring($nodestatmon);
  #      $rsp->{data}->[$i++]="node status monitoring with $nodestatmon: $msg"; 
  #    }
  #  }
  #}

  my $table=xCAT::Table->new("monitoring", -create => 1,-autocommit => 1);
  if ($table) {
    (my $ref) = $table->getAttribs({name => $pname}, name);
    if ($ref and $ref->{name}) {
      my %rsp;
      $rsp->{data}->[0]="$pname has already been activated for monitoring.";
      $callback->($rsp);
    }
    else {
      #update the monsetting table
      if ($settings) {  
        my $table1=xCAT::Table->new("monsetting", -create => 1,-autocommit => 1);
        my %key_col1 = (name=>$pname);
        #parse the settings. Setting format: key="value",key="value"....
        while ($settings =~ s/^\[([^\[\]\=]*)=([^\[\]]*)\](,)*//) { 
          $key_col1{key}=$1; 
	  $setting_hash{value}=$2;
          $table1->setAttribs(\%key_col1, \%setting_hash);
        }
        $table1->close();
      }

      #update the monitoring table
      my %key_col = (name=>$pname);
      my $nstat='N';
      if ($::NODESTATMON) {
	$nstat='Y';
      }
      my %tb_cols=(nodestatmon=>$nstat, disable=>"0");
      $table->setAttribs(\%key_col, \%tb_cols);
    }  
    $table->close(); 
  }

  #tell the service node to start monitoring too
  my $mon_hierachy=xCAT_monitoring::monitorctrl->getMonHierarchy();
  my @mon_servers=keys(%$mon_hierachy); 
  my @hostinfo=xCAT::Utils->determinehostname();
  #print "hostinfo=@hostinfo\n";
  %iphash=();
  foreach(@hostinfo) {$iphash{$_}=1;}
  foreach (@mon_servers) {
    #service node come in pairs, the first one is the monserver adapter that facing the mn,
    # the second one is facing the cn. we use the first one here
    my @server_pair=split(',', $_); 
    my $sv=$server_pair[0];
    if (! $iphash{$sv} && ($sv ne "noservicenode")) { #if it is not this node, meaning it is ms
      my %rsp2;
      $rsp2->{data}->[0]="sending request to $sv...";
      $callback->($rsp2);
#      my $result=`psh --nonodecheck $_ monupdate 2>1&`;     
#      if ($result) {
#        $rsp2->{data}->[0]="$result";
#        $callback->($rsp2);
#      }
      my %req=();
      push @{$req{command}}, "monupdate";
      $req{'_xcatdest'}=$sv;
      $doreq->(\%req,\&take_answer);
    } 
  } 

  my %rsp1;
  $rsp1->{data}->[0]="done.";
  $callback->($rsp1);

  return;
}

#--------------------------------------------------------------------------------
=head3   monstop
        This function unregisters the given monitoring plug-in from the 'monitoring' table.
        xCAT will ask the monitoring plug-in to stop the 3rd party software, which
        this plug-in connects to, to monitor the xCAT cluster. 
    Arguments:
      callback - the pointer to the callback function.
      args - The format of the args is:
        [-h|--help|-v|--version] or
        name
        where
          name is the monitoring plug-in name. For example: rmcmon. 
              The specified plug-in will be un-registered and stoped  
              for monitoring the xCAT cluster. 
    Returns:
        0 for success. The output is returned through the callback pointer.
        1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monstop {
  my $args=shift;
  my $callback=shift;
  my $doreq = shift;
  my $VERSION;
  my $HELP;

  if (xCAT::Utils->isServiceNode()) {
    my %rsp=();
    $rsp->{data}->[0]= "This command is not supported on a service node.";
    $callback->($rsp);
    return 0;
  }

  # subroutine to display the usage
  sub monstop_usage
  {
    my %rsp;
    $rsp->{data}->[0]= "Usage:";
    $rsp->{data}->[1]= "  monstop name";
    $rsp->{data}->[2]= "  monstop [-h|--help|-v|--version]";
    $rsp->{data}->[3]= "      name is the name of the monitoring plug-in module registered in the monitoring table.";
    $callback->($rsp);
  }

  @ARGV=@{$args};
  # parse the options
  if(!GetOptions(
      'h|help'     => \$::HELP,
      'v|version'  => \$::VERSION,))
  {
    &monstop_usage;
    return;
  }

  # display the usage if -h or --help is specified
  if ($::HELP) { 
    &monstop_usage;
    return;
  }

  # display the version statement if -v or --verison is specified
  if ($::VERSION)
  {
    my %rsp;
    $rsp->{data}->[0]= "monstop version 1.0";
    $callback->($rsp);
    return;
  }


  #my @product_names;
  my $pname;
  if (@ARGV < 1)
  {
    &monstop_usage;
    return;
  }
  else {
    #@product_names=split(/,/, $ARGV[0]);
    $pname=$ARGV[0];
  }

  #my %ret = xCAT_monitoring::monitorctrl::stopMonitoring(@product_names);
  #my %rsp;
  #$rsp->{data}->[0]= "stopping @product_names";
  #my $i=1;
  #foreach (keys %ret) {
  #  my $ret_array=$ret{$_};
  #  $rsp->{data}->[$i++]= "$_: $ret_array->[1]";
  #}

  #my $nodestatmon=xCAT_monitoring::monitorctrl::nodeStatMonName();
  #if ($nodestatmon) {
  #  foreach (@product_names) {
  #    if ($_ eq $nodestatmon) { 
  #	my ($code, $msg)=xCAT_monitoring::monitorctrl::stopNodeStatusMonitoring($nodestatmon);
  #      $rsp->{data}->[$i++]="node status monitoring with $nodestatmon: $msg"; 
  #    }
  #  }
  #}
  my $table=xCAT::Table->new("monitoring", -create => 1,-autocommit => 1);
  if ($table) {
    (my $ref) = $table->getAttribs({name => $pname}, name);
    if ($ref and $ref->{name}) {
      my %key_col = (name=>$pname);
      my %tb_cols=(disable=>"1");
      $table->setAttribs(\%key_col, \%tb_cols);
    }  
    else {
      my %rsp;
      $rsp->{data}->[0]="$pname was not registered or not activated.";
      $callback->($rsp);
    }
    $table->close();   
  }

  #tell all the service nodes to stop monitoring too
  my $mon_hierachy=xCAT_monitoring::monitorctrl->getMonHierarchy();
  my @mon_servers=keys(%$mon_hierachy); 
  my @hostinfo=xCAT::Utils->determinehostname();
  %iphash=();
  foreach(@hostinfo) {$iphash{$_}=1;}
  foreach (@mon_servers) {
    #service node come in pairs, the first one is the monserver adapter that facing the mn,
    # the second one is facing the cn. we use the first one here
    my @server_pair=split(',', $_); 
    my $sv=$server_pair[0];
    if (! $iphash{$sv} && ($sv ne "noservicenode")) { #if it is not this node, meaning it is ms
      my %rsp2;
      $rsp2->{data}->[0]="sending request to $sv...";
      $callback->($rsp2);
      # my $result=`psh --nonodecheck $_ monupdate 2>1&`;     
      # if ($result) {
      #  $rsp2->{data}->[0]="$result";
      #  $callback->($rsp2);
      #}  
      my %req=();
      push @{$req{command}}, "monupdate";
      $req{'_xcatdest'}=$sv;
      $doreq->(\%req,\&take_answer);
    } 
  } 

  my %rsp1;
  $rsp1->{data}->[0]="done.";
  $callback->($rsp1);
  
  return;
}


#--------------------------------------------------------------------------------
=head3   monls
        This function list the monitoring plug-in module names, status and description. 
    Arguments:
      callback - the pointer to the callback function.
      args - The format of the args is:
        [-h|--help|-v|--version] or
        [name] [-a|all] [-d|--description]         
    Returns:
        0 for success. The output is returned through the callback pointer.
        1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monls {
  my $args=shift;
  my $callback=shift;
  my $VERSION;
  my $HELP;

  # subroutine to display the usage
  sub monls_usage
  {
    my %rsp;
    $rsp->{data}->[0]= "Usage:";
    $rsp->{data}->[1]= "  monls name [-d|--description]";
    $rsp->{data}->[2]= "  monls [-a|--all] [-d|--description]";
    $rsp->{data}->[3]= "  monls [-h|--help|-v|--version]";
    $rsp->{data}->[4]= "     name is the name of the monitoring plug-in module.";
    $callback->($rsp);
  }
  
  @ARGV=@{$args};

  # parse the options
  if(!GetOptions(
      'h|help'     => \$::HELP,
      'v|version'  => \$::VERSION,
      'a|all'  => \$::ALL,
      'd|discription'  => \$::DESC))
  {
    &monls_usage;
    return;
  }

  # display the usage if -h or --help is specified
  if ($::HELP) { 
    &monls_usage;
    return;
  }

  # display the version statement if -v or --verison is specified
  if ($::VERSION)
  {
    my %rsp;
    $rsp->{data}->[0]= "monls version 1.0";
    $callback->($rsp);
    return;
  }

  my %names=();
  my $plugin_dir="$::XCATROOT/lib/perl/xCAT_monitoring";
  my $usetab=0;
  if (@ARGV > 0)
  {
    $names{$ARGV[0]}=0;
  }
  else {
    if ($::ALL) {
      #get all the module names from /opt/xcat/lib/perl/XCAT_monitoring directory   
      my @plugins=glob($plugin_dir."/*.pm");
      foreach (@plugins) {
        /.*\/([^\/]*).pm$/;
        $names{$1}=0;
      }
      # remove 2 files that are not plug-ins
      delete($names{monitorctrl});
      delete($names{montbhandler});
    }
    else {
      $usetab=1;
    }
  }

  #get the list from the table
  my $table=xCAT::Table->new("monitoring", -create =>1);
  if ($table) {
    my $tmp1=$table->getAllEntries();
    if (defined($tmp1) && (@$tmp1 > 0)) {
      foreach(@$tmp1) {
        my $pname=$_->{name};
        if (($usetab) || exists($names{$pname})) {
          $names{$pname}=1;
          my $monnode=0;
          my $disable=1;
          if ($_->{nodestatmon} =~ /1|Yes|yes|YES|Y|y/) { $monnode=1; }
          if ($_->{disable} =~ /0|NO|No|no|N|n/) { $disable=0; }
          my %rsp;
          $rsp->{data}->[0]="$pname\t\t". 
                             ($disable ? "not-monitored" : "monitored") . 
                             ($monnode ? "\tnode-status-monitored" : "");
          if ($::DESC) {
            #find out the monitoring plugin file and module name for the product
            my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
            my $module_name="xCAT_monitoring::$pname";
            #load the module in memory
            eval {require($file_name)};
            if ($@) {   
              $rsp->{data}->[1]="  Description:\n    not available. The file $file_name cannot be located or has compiling errors."; 
            }
            else {
              $rsp->{data}->[1]=${$module_name."::"}{getDescription}->() . "\n";  
	    }
          }
          $callback->($rsp);
	}
      } #foreach
    }
    $table->close();
  }

    
  #now handle the ones that are not in the table
  foreach(keys(%names)) {
    my $pname=$_;
    if ($names{$pname}==0) {
      my %rsp;
      $rsp->{data}->[0]="$pname\t\tnot-monitored";
      if ($::DESC) {
        #find out the monitoring plugin file and module name for the product
        my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
        my $module_name="xCAT_monitoring::$pname";
        #load the module in memory
        eval {require($file_name)};
        if ($@) {   
          $rsp->{data}->[1]="  Description:\n    not available. The file $file_name cannot be located or has compiling errors."; 
        }
        else {
          $rsp->{data}->[1]=${$module_name."::"}{getDescription}->(). "\n";  
        }
      }
      $callback->($rsp);
    }
  }
  return;
}


#--------------------------------------------------------------------------------
=head3   monaddnode
        This function informs all the active monitoring plug-ins to add the given
     nodes to their monitoring domain 
    Arguments:
      callback - the pointer to the callback function.
      args - The format of the args is:
        [-h|--help|-v|--version] or
        noderange
    Returns:
        0 for success. The output is returned through the callback pointer.
        1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monaddnode {
  my $args=shift;
  my $callback=shift;
  my $VERSION;
  my $HELP;

  # subroutine to display the usage
  sub monaddnode_usage
  {
    my %rsp;
    $rsp->{data}->[0]= "Usage:";
    $rsp->{data}->[1]= "  monaddnode noderange";
    $rsp->{data}->[2]= "  monaddnode [-h|--help|-v|--version]";
    $rsp->{data}->[3]= "      noderange is a list of comma separated node or node group names.";
    $callback->($rsp);
  }

  @ARGV=@{$args};
  # parse the options
  if(!GetOptions(
      'h|help'     => \$::HELP,
      'v|version'  => \$::VERSION,
      'local'  => \$::LOCAL,)) # this flag is used internally to indicate
                                   # that there is no need to find the monserver for the nodes
                                   # just handle them on the lccal host
  {
    &monaddnode_usage;
    return;
  }

  # display the usage if -h or --help is specified
  if ($::HELP) { 
    &monaddnode_usage;
    return;
  }

  # display the version statement if -v or --verison is specified
  if ($::VERSION)
  {
    my %rsp;
    $rsp->{data}->[0]= "monaddnode version 1.0";
    $callback->($rsp);
    return;
  }


  my $noderange;
  if (@ARGV < 1)
  {
    &monaddnode_usage;
    return;
  }
  else {
    $noderange=$ARGV[0];
  }

  my @nodenames=noderange($noderange);
  my @missed=nodesmissed();
  if (@missed > 0) {
    my %rsp1;
    $rsp1->{data}->[0]="Invalide nodes:@missed";
    $callback->($rsp1);
    return;
  }

  my %ret=xCAT_monitoring::monitorctrl->addNodes(\@nodenames,$::LOCAL);

  if (%ret) {
    foreach(keys(%ret)) {
      my $retstat=$ret{$_}; 
      my %rsp1;
      $rsp1->{data}->[0]="$_: @$retstat";
      $callback->($rsp1);
    }
  }
 
  return 0;


}




#--------------------------------------------------------------------------------
=head3   monrmnode
        This function informs all the active monitoring plug-ins to remove the given
     nodes to their monitoring domain 
    Arguments:
      callback - the pointer to the callback function.
      args - The format of the args is:
        [-h|--help|-v|--version] or
        noderange
    Returns:
        0 for success. The output is returned through the callback pointer.
        1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monrmnode {
  my $args=shift;
  my $callback=shift;
  my $VERSION;
  my $HELP;

  # subroutine to display the usage
  sub monrmnode_usage
  {
    my %rsp;
    $rsp->{data}->[0]= "Usage:";
    $rsp->{data}->[1]= "  monrmnode noderange";
    $rsp->{data}->[2]= "  monrmnode [-h|--help|-v|--version]";
    $rsp->{data}->[3]= "      noderange is a list of comma separated node or node group names.";
    $callback->($rsp);
  }

  @ARGV=@{$args};
  # parse the options
  if(!GetOptions(
      'h|help'     => \$::HELP,
      'v|version'  => \$::VERSION,
      'local'  => \$::LOCAL,)) # this flag is used internally to indicate
                                   # that there is no need to find the monserver for the nodes
                                   # just handle them on the lccal host

  {
    &monrmnode_usage;
    return;
  }

  # display the usage if -h or --help is specified
  if ($::HELP) { 
    &monrmnode_usage;
    return;
  }

  # display the version statement if -v or --verison is specified
  if ($::VERSION)
  {
    my %rsp;
    $rsp->{data}->[0]= "monrmnode version 1.0";
    $callback->($rsp);
    return;
  }


  my $noderange;
  if (@ARGV < 1)
  {
    &monrmnode_usage;
    return;
  }
  else {
    $noderange=$ARGV[0];
  }

  my @nodenames=noderange($noderange, 0);
  if (@nodenames==0) { return 0;}

  my %ret=xCAT_monitoring::monitorctrl->removeNodes(\@nodenames, $::LOCAL);
  if (%ret) {
    foreach(keys(%ret)) {
      my $retstat=$ret{$_}; 
      my %rsp1;
      $rsp1->{data}->[0]="$_: @$retstat";
      $callback->($rsp1);
    }
  }
 
  return 0;

}



#--------------------------------------------------------------------------------
=head3  moncfgmaster 
        This function goes asks the monitoring plug-ins to configure the local host
     to include the given nodes into the monitoring domain. (The nodes configuration 
     is done via post installation scripts during deployment process).
    Arguments:
      nodes  - a pointer to a array of nodes.
      callback - the pointer to the callback function.
    Returns:
        0 for success. The output is returned through the callback pointer.
        1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub moncfgmaster {
  my $noderef=shift;
  my $callback=shift;
  
  my ($ret, $msg) = xCAT_monitoring::monitorctrl->configMaster4Nodes($noderef);
  if ($ret) {
    my %rsp1;
    $rsp1->{data}->[0]="$msg";
    $callback->($rsp1);
  }  
  return $ret;
}