#!/usr/sbin/rsct/perl5/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2001,2007 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
#"@(#)82   1.25   src/rsct/rm/ConfigRM/cli/bin/mkrpdomain.perl, configrmcli, rsct_relgh, relghs001a 2/23/07 08:54:19"
######################################################################
#                                                                    #
# Module: mkrpdomain                                                 #
#                                                                    #
# Purpose:                                                           #
#   mkrpdomain - makes a new RSCT peer domain definition.            #
#                                                                    #
# Syntax:                                                            #
#   mkrpdomain [-h]  [-t HATS_port]  [-g HAGS_port]  [-r RMC_port]   #
#              [-k Key_type] [-r Interval_expr] [-u Admin_id] [-c]   #
#              [-Q QuorumTypeName|QuorumTypeValue]                   # 
#              [-G QuorumGroupName]                                  #
#	       [-m Fanout]					     #
#              [-TV] PeerDomain [Node_name [Node_name ...]]          #
#                                                                    #
#   mkrpdomain [-h]  [-t HATS_port]  [-g HAGS_port]  [-r RMC_port]   #
#              [-k Key_type] [-r Interval_expr] [-u Admin_id] [-c]   #
#              [-Q QuorumTypeName|QuorumTypeValue]                   # 
#              [-G QuorumGroupName]                                  #
#	       [-m Fanout]					     #
#              -f File|-F File [-TV] PeerDomain                      #
# Flags:                                                             #
#   -h      Help. Writes the command's usage statement to standard   #
#           output.                                                  #
#   -t HATS_port   The HATS Port number. This is the UDP port that   #
#           will be used for daemon-to-daemon communication.  Any    #
#           unused port in the range 1024 - 65535 may be assigned.   #
#           The command will fail if the specified port is           #
#           unavailable.  The default is 12347.                      #
#   -g HAGS_port   The HAGS Port number. This is the UDP port that   #
#           will be used for daemon-to-daemon communication.  Any    #
#           unused port in the range 1024 - 65535 may be assigned.   #
#           The command will fail if the specified port is           #
#           unavailable.  The default is 12348.                      #
#   -c      Continue on error.  Do not stop when an error occurs but #
#           continue processing the mkrpdomain command as long as at #
#           least one node can be included in the peer domain.       #
#   -f File The file containing the nodes names to be defined to the #
#           peer domain. The node names are defined as Node_name     #
#           operands or in a file, not both.  When in a file, each   #
#           line of the file is scanned for one node name.  Comments #
#           may be placed on each line, but after the comment        #
#           character "#". Lines that start (col 1) with "#" or are  #
#           entirely blank are ignored.  Use -f "-" to specify STDIN #
#           as the input file.                                       #
#   -F File Same as -f.                                              #
#   -k Key_type    The peer domain shared secret key.                #
#           The default is none (or CSSKTYPE_None).                  #
#   -r Interval_expr  The cluster shared secret key refreh interval. #
#           The interval expression is in the for dd:hh:mm:ss.       #
#           The leftmost of the expression must be specified.  For   #
#           example, -r 20 means 20 days.  -r 0 means never refresh. #
#           The default is 1 day.                                    #
#   -u Admin_id    The administrator user ID.  This user ID will be  #
#           granted read/write permission to all resource classes    #
#           on all nodes in the peer domain.                         #
#   -Q QuorumTypeName|QuorumTypeValue   The Quorum Type to use.  The #
#           quorum type can be specified as a name or a value.  A    #
#           valid quorum name can be found from the                  #
#           AvailableQuorumTypes class attribute on IBM.PeerDomain.  #
#   -G QuorumGroupName  The Quorum group name.  Specifies the group  #
#           name for the quorum.                                     #
#   -m Fanout	max number of threads to use in parallel operations  #
#	    for this RPD, stored as persistent attr in its	     #
#	    IBM.PeerNode class.  If unspecified, hardcoded default   #
#	    in ConfigRM is used.				     #
#   -T      Trace. Writes the command's trace messages to standard   #
#           error. For your software-service organization's use only.#
#   -V      Verbose. Writes the command's verbose messages to        #
#           standard output.                                         #
#                                                                    #
# Operands:                                                          #
#   PeerDomain  The name of the new RSCT peer domain to be created.  #
#               The name may contain any printable character. The    #
#               name must not be IW.                                 #
#   Node_name   The node to include in this peer domian definition.  #
#               The node name is the long or short version of the    #
#               DNS hostname.  It must be resolvable to an IP        #
#               address. At least one node name must be specified.   #
#               The node names can be specifed as operands or in a   #
#               file using the -f flag, but not both.                #
#                                                                    #
# Description:                                                       #
#   The mkrpdomain command creates a new peer domain definition with #
#   the name specified by the PeerDomain operand.  The nodes         #
#   specified by Node_name, or node names defined in a file using    #
#   the -f flag are defined to the new peer domain.  A peer domain   #
#   can be used to provide highly available services when            # 
#   configuring application and system resources.                    #
#                                                                    #
#   The mkrpdomain command does not bring the peer domain online     #
#   automatically. To bring the ipeer domainr online, run the        #
#   startrpdomain command.  Nodes can be added to and removed from   #
#   the peer domain cluster by using the addrpnode and rmrpnode      #
#   commands.                                                        #
#                                                                    #
#   A node can be defined in more than one peer domain but it can be #
#   online in only one peer domain at a time.                        #
#                                                                    #
#   The conditions which must be met for a node to join a peer       #
#   domain are:                                                      #
#      o rsct.basic must be installed                                #
#      o must be able to establish trust between nodes               #
#      o must be in the same kerberos realm                          #
#      o must be able to exchange public key                         #
#                                                                    #
#   Only those nodes that meet the above requirements will be        #
#   successfully defined to the peer domain.                         #
#                                                                    #
#   If the UDP port numbers for HATS, HAGS, and RMC are not available#
#   on all of the nodes to be defined to the peer domain, the        #
#   mkrpdomain command will fail.  Otherwise, the peer domain        #
#   definition is created and the nodes are added to the peer domain #
#   if they meet the above conditions.  The command will also fail   #
#   if the cluster name is already being used.                       # 
#                                                                    #
# Exit Values:                                                       #
#   0  CRM_CLI_SUCCESS       Command completed successfully.         #
#   1  CRM_CLI_RMC_ERROR     Command terminated due to an underlying #
#                            RMC error.                              #
#   2  CRM_CLI_ERROR         Command terminated due to an underlying #
#                            error in the command script.            #
#   3  CRM_CLI_BAD_FLAG      Command terminated due to user          #
#                            specifying an invalid flag.             #
#   4  CRM_CLI_BAD_OPERAND   Command terminated due to user          #
#                            specifying a bad operand.               #
#   5  CRM_CLI_USER_ERROR    Command terminated due to a user error, #
#                            for example specifying a name that      #
#                            already exists.                         #
#                                                                    #
# Examples:                                                          #
#   1. To define a peer domain consisting of nodeA with the peer     #
#      domain name ApplDomain, run the following command on nodeA:   #
#      mkrpdomain ApplDomain                                         #
#                                                                    #
#   2. To define a peer domain consisting of nodeA, nodeB, and nodeC,#
#      with the peer domain name ApplDomain, run the following       #
#      command on nodeA, nodeB, or NodeC:                            #
#      mkrpdomain ApplDomain nodeA nodeB nodeC                       #
#                                                                    #
#   3. To define a peer domain consisting of nodeA and nodeB, with   #
#      peer domain name ApplDomain,  HATS Port number 1200,  HAGS    #
#      Port number 2400, and RMC Port number 3600, run the following #
#      command on nodeA or nodeB:                                    #
#      mkrpdomain -t 1200 -g 2400 -r 3600 ApplDomain nodeA nodeB     #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the mkrpdomain man page in /usr/sbin/rsct/man.                   #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /usr/sbin/rsct/msgmaps/configrmcli.mkrpdomain.map -              # 
#       message mapping                                              #
#                                                                    #
# Outputs:                                                           #
#   stdout - none.                                                   #
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  CRM_cli_utils.pm, CRM_cli_rc.pm,                       #
#             CRM_cli_include.pm, CT_cli_utils.pm                    #
#   Perl library routines: Getopt::Std                               #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   010806 JAC 75435: Initial design & write.                        #
#   010827 JAC 75436: Implement node operand, check name for spaces. #
#   011218 JAC 78807: remove port checking and don't resolve names.  #
#   020107 JAC 77329: security feature, add -k, -r, and -u.          #
#   020131 JAC 79963: switch to use mkrsrc-api instead of mkrsrc.    #
#   020205 JAC 80060: require at least one node name for operand.    #
#   020207 JAC 80121: Make printing of c-api results a trace msg.    #
#   020327 JAC 81370: Add -f flag to read node names from a file.    #
#   020415 JAC 82055: Add -c for continue-on-error.                  #
#   020417 JAC 81859: Add node numbers to file support.              #
#   020419 JAC 82248: Rename mkcluster to mkrpdomain.                #
#   020428 JAC 82316: Call process_exit_code to check $rc.           #
#   020502 JAC 82564: Set local scope before calling mkrsrc-api.     #
#   030324 JAC 93122: Don't specify default command arguments.       #
#   040319 JAC 105987: Add -F flag to do the same as -f.             #
#   040329 JAC 102042: Add -Q and -G quorum flags.                   #
#   040407 JAC 105863: Use escape_chars for "\" searches.            #
#   040427 JAC 107926: Restrict the name to A-Z,a-z,0-9,.,_..        #
#   041118 JMS 104741: make ConfigRM RMC thread fanout configurable  #
#   050124 JMS 116382: -m instead of -n for fanout                   #
#   050406 JAC 119510: Add rc when calling process_api_error.        #
#   051025 JAC 125712: Use mkrsrc-api -f option when cmd too long.   #
#   061220 JAC 140962: Some changes for implementing -k and -r.      #
#   070222 JAC 141884: pass default refresh interval differently.    #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# 1. Parse command line flags and operands.                          #
# 2. Print usage if -h specified                                     #
# 3. Make sure the cluster name specified is not IW, has no spaces,  #
#    and doesn't already exist.                                      #
# 4. Verify the ports arguments.                                     #
# 5. Resolve any node names specified.                               #
# 6. Call RMC command mkrsrc. Also pass along -VT if necessary.      #
# 7. Return back any errors.                                         #
#                                                                    #
#--------------------------------------------------------------------#

#--------------------------------------------------------------------#
# Included Libraries and Extensions                                  #
#--------------------------------------------------------------------#
use lib "/usr/sbin/rsct/pm";
use locale;
use Getopt::Std;

use CT_cli_utils qw(printIMsg
                    printEMsg
                    calc_cmdarg_length);
use CT_cli_input_utils qw(escape_chars);

use CRM_cli_rc qw(CRM_CLI_SUCCESS CRM_CLI_RMC_ERROR
                  CRM_CLI_ERROR CRM_CLI_BAD_FLAG
                  CRM_CLI_BAD_OPERAND CRM_CLI_USER_ERROR);
use CRM_cli_utils qw(error_exit
                     printCIMsg
                     printCEMsg
                     resolve_node_names
                     process_api_error
                     process_exit_code
                     check_quorum_type
                     get_nodes_nums_from_file
                     get_opstate_by_name);
use CRM_cli_include qw($TRUE $FALSE
                       $RSCLUSTER $RMC_CLI_USER_ERROR
                       $LOCAL_SCOPE
                       $CTBINDIR $CTDIR);

#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
$Trace = $FALSE;                        # default - trace off
$Verbose = $FALSE;                      # default - verbose turned off

$Opt_Hatsport = $FALSE;                 # default - no HATS port
$Opt_Hagsport = $FALSE;                 # default - no HAGS port
$Opt_CSSKType = $FALSE;                 # default - no CSSK type
$Opt_Continue = $FALSE;                 # default - no continue on error
$Opt_CSSKRefresh = $FALSE;              # default - no CSSK refresh
$Opt_AdminUID = $FALSE;                 # default - no admin user id
$Opt_File_Input = $FALSE;               # default - no file
$Opt_QuorumType = $FALSE;               # default - no quorum type
$Opt_GroupQ = $FALSE;                   # default - no group quorum name
$Opt_Fanout = $FALSE;			# default - no fanout specd

$PROGNAME = "mkrpdomain";               # Program Name for messages
$LSMSG = "$CTBINDIR/ctdspmsg";          # list / display message rtn
$MSGCAT = "configrmcli.cat";            # msg catalogue for this cmd
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # msg maps used by $LSMSG

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my $cluster_name = "";                  # cluster to create
my $hats_port = 0;                      # HATS port  
my $hags_port = 0;                      # HAGS port  
my $cssk_type = "";                     # CSSK type
my $refresh_interval = "";              # CSSK refresh interval (char)
my $admin_uid = "";                     # administrator user id
my @node_names = ();                    # nodes in cluster
my @node_numbers = ();                  # nodes in cluster
my @clusters = ();                      # nodes in the hash
my $resolved_node_names = "";           # resolved node names
my $unresolved_node_names = "";         # unresolved node names
my $resolved_node_list = "";            # resolved node list
my $one_node = "";                      # one from nodelist
my $comma = "";                         # used to build a list
my %cluster_opstates = ();              # shows cluster name and opstate
my $translated_interval = 0;            # translated refresh interval
my $d = 0;                              # refresh days
my $h = 0;                              # refresh hours
my $m = 0;                              # refresh minutes
my $s = 0;                              # refresh seconds
my @cmd_out = ();                       # for mkrsrc output
my $interval_invalid = $FALSE;          # check for bad refresh interval
my $file_name = "";                     # file name for node names
my $file_error = "";                    # error with file
my $node_names_file = "";               # reference to node names
my $node_nums_file = "";                # reference to node numbers
my $node_num_list = "";                 # for rmc command
my $one_num = "";                       # one from node num list
my $q_type = "";                        # quorum type
my $q_group = "";                       # quorum group name
my $fanout = 0;				# thread fanout
my $parmlen = 0;                        # length of parms to pass to mkrsrc-api

my $passopts = "";                      # TV options to pass to RMC CLI
my $other_opts = "";                    # parameters to pass to RMC CLI
#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
my $rc = 0;
my $config_rc = 0;

# set local scope
$ENV{CT_MANAGEMENT_SCOPE} = $LOCAL_SCOPE;

# parse the command line, exit if there are errors 
($rc, $hats_port, $hags_port, $cssk_type, $refresh_interval, 
 $admin_uid, $file_name, $cluster_name, $q_type, $q_group, 
 @node_names) = &parse_cmd_line;
($rc == 0) || error_exit($rc);

if ($Verbose) { printIMsg("IMsgmkrpdomainStart",$cluster_name); }

if ($Trace) { $passopts = $passopts." -T"; }
if ($Verbose) { $passopts = $passopts." -V"; }

# get the command line buffer length
$CMD_LIMIT = calc_cmdarg_length;

# Do some escaping on strings.  Do the escape character first
# for anything that's a string, escape any inner \
#$cluster_name =~ s/\\/\\\\/g;

# for anything that's a string, escape any inner double quotes
#$cluster_name =~ s/\"/\\\"/g;

$cluster_name = escape_chars($cluster_name);

# make sure cluster name is not IW
if ($cluster_name eq "IW") {
         printEMsg("EMsgmkrpdomainNameIW");
         exit (CRM_CLI_USER_ERROR);
      }

# make sure cluster name does not contain spaces
if ($cluster_name =~ / /) {
         printEMsg("EMsgmkrpdomainNameSpaces",$cluster_name);
         exit (CRM_CLI_USER_ERROR);
      }

# make sure cluster name only contains A-Z, a-z, 0-9, . (period), _ (underscore)
if ($cluster_name !~ /^[A-Za-z0-9._]+$/) {
         printEMsg("EMsgmkrpdomainNameBad");
         exit (CRM_CLI_USER_ERROR);
      }

# get the node names from a file, if specified 
if ($Opt_File_Input) {
   
   # extract the node names from the file
   ($node_names_file, $node_nums_file) = get_nodes_nums_from_file($file_name);

   # copy to other array
   @node_names = @$node_names_file;
   @node_numbers = @$node_nums_file;
}

# make sure cluster name doesn't already exist
#HOW? or let RM do it (which it does, just means different rc)

# make sure this node is not already in this cluster
# get the cluster opstate info
%cluster_opstates = get_opstate_by_name($RSCLUSTER);

# get a list of the cluster names for this node
@clusters = keys %cluster_opstates;

# make sure the cluster name doesn't exist
foreach $one_cluster (@clusters) {
   if ($one_cluster eq $cluster_name) {
      printEMsg("EMsgmkrpdomainClusterExists",$cluster_name);
      exit(CRM_CLI_USER_ERROR);
   }
}

# pass in HATS port if specified
if ($Opt_Hatsport) {                    # -t used for hats port 
   $other_opts = $other_opts."::TSPort::$hats_port";
}

# pass in HAGS port if specified
if ($Opt_Hagsport) {                    # -g used for hags port 
   $other_opts = $other_opts."::GSPort::$hags_port";
}

# pass in Admin user ID if specified
if ($Opt_AdminUID) {                    # -u used for admin ID
   $other_opts = $other_opts."::AdminID::$admin_uid";
}

# pass in quorum type, if specified
if ($Opt_QuorumType) {                # -Q used for quorum type
   $other_opts = $other_opts."::QuorumType::$q_type";
}

# pass in quorum group, if specified
if ($Opt_GroupQ) {                    # -G used for quorum group name
   $other_opts = $other_opts."::QuorumGroupName::$q_group";
}

# resolve node names that are to be added to the cluster
# resolve any node names to be in the cluster
($resolved_node_names, $unresolved_node_names) = resolve_node_names(@node_names);

# write an error message for each unresolved node name found
# continue processes but set rc
foreach $one_node (@$unresolved_node_names) {
   printEMsg("EMsgmkrpdomainUnresolvedNode",$one_node);
   $config_rc = CRM_CLI_USER_ERROR; 
}

# exit if there were unresolved names
if ($config_rc != 0) {
   exit ($config_rc);
}

# make a list of the node names to pass to rmc
$comma = "";
foreach $one_node (@node_names) {
   $resolved_node_list = $resolved_node_list.$comma.$one_node;
   $comma = ",";
}

# make a list of the node numbers to pass to rmc
$comma = "";
foreach $one_num (@node_numbers) {
   $node_num_list = $node_num_list.$comma.$one_num;
   $comma = ",";
}

# the setting of attributes after this point is for command args

# setup the nodelist
$other_opts = $other_opts."::::NodeNames::{$resolved_node_list}";

# setup node number list
$other_opts = $other_opts."::NodeNumbers::{$node_num_list}";

# continue on error specified?
if ($Opt_Continue) {
   $other_opts = $other_opts."::ContinueIfError::1";
}
#93122 - comment out specifying the default command argument
#else {
#   $other_opts = $other_opts."::ContinueIfError::0";
#}

# pass in fanout, if specified
if ($Opt_Fanout) {			# -n used for thread fanout
   $other_opts = $other_opts."::Fanout::$fanout";
}

# pass in CSSK type if specified
if ($Opt_CSSKType) {                    # -k used for key type
   $other_opts = $other_opts."::CSSKType::$cssk_type";
}

# translate and pass in CSSK refresh interval if specified
if ($Opt_CSSKRefresh) {                 # -r used for refresh
                                        # (-r requires -k)

   # parse out the refresh values days:hours:minutes:seconds
   ($d, $h, $m, $s) = split /:/, $refresh_interval;

   # if any are not used, set to 0
   if (!defined $d ) { $d = 0;}
   if ($h eq "") { $h = 0;}
   if ($m eq "") { $m = 0;}
   if ($s eq "") { $s = 0;}

   # make sure they are digit values
   if ($d =~ /\D+/) { $interval_invalid = $TRUE;}
   if ($h =~ /\D+/) { $interval_invalid = $TRUE;}
   if ($m =~ /\D+/) { $interval_invalid = $TRUE;}
   if ($s =~ /\D+/) { $interval_invalid = $TRUE;}

   # exit if the interval is bad
   if ($interval_invalid) {
      printEMsg("EMsgmkrpdomainBadInterval");
      exit (CRM_CLI_USER_ERROR);
   }
   else {
      # calculate the total number of seconds
      $translated_interval = ($d * 24 * 60 * 60) +
                             ($h * 60 * 60) +
                             ($m * 60) + $s;

      # if seconds are 0, set to -1 for never refresh
      # defect 141884 comments out the next line
      #if ($translated_interval == 0) { $translated_interval = -1;}

      # pass the interval attribute value
      $other_opts = $other_opts."::CSSKRefreshInterval::$translated_interval";
   }
}

# if -k was specified but not -r, tell ConfigRM to use default by passing -1
# (141884)
if ($Opt_CSSKType && !$Opt_CSSKRefresh) { 

      $translated_interval = -1;
      $other_opts = $other_opts."::CSSKRefreshInterval::$translated_interval";
}

# Prepare to call mkrsrc-api
# get the total length for the command to see if the command buffer will be exceeded
$parmlen = length($CTBINDIR) + length($RSCLUSTER) + length($cluster_name) 
           + length($other_opts) + 50;

# decide how to call mkrsrc-api based on the command length
if ($parmlen > $CMD_LIMIT) {
   # use mkrsrc-api with file option
   $rc = mkrsrcapi_file($cluster_name, $other_opts);
}
else {
   # use mkrsrc-api using the command buffer
   $rc = mkrsrcapi_cmdline($cluster_name, $other_opts);
}

# return ConfigRM CLI user error if it's an RMC CLI user error
if ($rc == $RMC_CLI_USER_ERROR) { exit(CRM_CLI_USER_ERROR);}

# if mkrsrc failed for something else, print RMC error message and exit
if ($rc != 0) {
#   printCEMsg("EMsgConfigRMcliUnExpectRMCrc",$rc);
    exit(CRM_CLI_RMC_ERROR);
    }

if ($Verbose) { printIMsg("IMsgmkrpdomainEnd",$cluster_name); }

if ($config_rc == 0) { exit($rc); }
else { exit($config_rc); } 

#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line - Parse the command line for options and operands.  #
#   Set appropriate global variables as outlined below, make sure we #
#   have a valid combination of arguments / options.                 #
#                                                                    #
# Return:                                                            #
#   $rc   0                  Command line parsed fine, no problem.   #
#         CRM_CLI_BAD_FLAG   Command line contained a bad flag.      #
#   $cluster_name            Name of cluster to create.              #
#   $hats_port               HATS port                               #
#   $hags_port               HAGS port                               #
#   $cssk_type               CSSK type                               #
#   $refresh_interval        CSSK refresh interval                   #
#   $admin_uid               Administrator user ID                   #
#   @node_names              Nodes to belong to the cluster          #
#   $file_name               File containing node names              #
#   $q_type                  Quorum type                             #
#   $q_group                 Quorum group name                       #
#                                                                    #
# Global Variables Modified:                                         #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#   $Trace             output   True (-T) turn Trace mode on.        #
#   $Opt_Hatsport      output   True (-t) HATS port specified        #
#   $Opt_Hagsport      output   True (-g) HAGS port specified        #
#   $Opt_CSSKType      output   True (-k) CSSK type specified        #
#   $Opt_CSSKRefresh   output   True (-r) CSSK refresh int specified #
#   $Opt_AdminUID      output   True (-u) Admin user ID specified    #
#   $Opt_File_Input    output   True (-f|-F) file name specified     #
#   $Opt_Continue      output   True (-c) Continue on error          #
#   $Opt_QuorumType    output   True (-Q) Quorum type                #
#   $Opt_GroupQ        output   True (-G) Quorum group name          #
#--------------------------------------------------------------------#
sub parse_cmd_line 
{
my(@original_argv) = @ARGV;
my $cluster_name = "";                  # cluster name    
my $hats_port = 0;                      # HATS port 
my $hags_port = 0;                      # HAGS port 
my $rmc_port = 0;                       # RMC port 
my $cssk_type = "";                     # CSSK type
my $refresh_interval = "";              # CSSK refresh interval
my $admin_uid = "";                     # Admin user ID
my $file_name = "";                     # file name
my $q_type = "";                        # quorum type
my $q_group = "";                       # quorum group name
my @node_names = ();                    # node names
my %opts = ();

# Process the command line...
if (!&getopts('ht:g:G:Q:k:r:cu:f:F:m:VT', \%opts)) { # Gather options; 
                                        # if errors
    &print_usage;                       # display proper usage
    return CRM_CLI_BAD_FLAG;            # return bad rc - bad flag 
}

# process h flag
if (defined $opts{h}) {                 # -h, help request
    &print_usage;                       # print usage statement
    exit(0);                            # all done with good return!
}

if (defined $opts{T}) {                 # -T turn trace on
    $Trace = $TRUE;
}

if (defined $opts{V}) {                 # -V turn verbose mode on
    $Verbose = $TRUE;
}

# Get the arguments...cluster name followed by node names
if ($#ARGV >= 0) {                      # cluster name
   $cluster_name = shift @ARGV;         # get cluster name
}
else {            
    # cluster name not specified 
    printCEMsg("EMsgConfigRMcliInvalidNumberOfOperands");
    &print_usage;
    return CRM_CLI_BAD_OPERAND;
}

# Get the node names   
if ($#ARGV >=0) {                       # node names
   @node_names = @ARGV;                 # get node names
}

# make sure -f or -F for file used if there are no node names
if (($#node_names < 0) && !(defined $opts{f}||defined $opts{F})) {
    printCEMsg("EMsgConfigRMcliInvalidNumberOfOperands");
    &print_usage;
    return CRM_CLI_BAD_OPERAND;
}

if (defined $opts{f}) {                 # -f for file

    # make sure both -f and -F not used together 
    if (defined $opts{F}) { 
       printCEMsg("EMsgConfigRMcliImproperUsageCombination","-f","-F");
       &print_usage;
       return CRM_CLI_BAD_FLAG;
   }
    $Opt_File_Input = $TRUE;
    $file_name = $opts{f};         
    # make sure file and cmd line not both used for node names
    if ($#node_names >= 0) {
       printCEMsg("EMsgConfigRMcliInvalidNumberOfOperands");
       &print_usage;
       return CRM_CLI_BAD_OPERAND;
   }
}

if (defined $opts{F}) {                 # -F for file
    $Opt_File_Input = $TRUE;
    $file_name = $opts{F};
    # make sure file and cmd line not both used for node names
    if ($#node_names >= 0) {
       printCEMsg("EMsgConfigRMcliInvalidNumberOfOperands");
       &print_usage;
       return CRM_CLI_BAD_OPERAND;
   }
}
 
if (defined $opts{t}) {                 # -t for HATS port
    $hats_port = $opts{t};         
    $Opt_Hatsport = $TRUE;              # -t flag specified
}

if (defined $opts{g}) {                 # -g for HAGS port
    $hags_port = $opts{g};         
    $Opt_Hagsport = $TRUE;              # -g flag specified
}

if (defined $opts{k}) {                 # -k for CSSK type
    $cssk_type = $opts{k};         
    $Opt_CSSKType = $TRUE;              # -k flag specified
}

if (defined $opts{r}) {                 # -r for refresh interval
    if (!defined $opts{k}) {            # -k must be specified too
       printEMsg("EMsgmkrpdomainRNeedsK");
       &print_usage;
       return CRM_CLI_BAD_FLAG;
    }
    $refresh_interval = $opts{r};         
    $Opt_CSSKRefresh = $TRUE;           # -r flag specified
}
 
if (defined $opts{c}) {                 # -c for continue on error
    $Opt_Continue = $TRUE;              # -c flag specified
}

if (defined $opts{u}) {                 # -u for admin ID
    $admin_uid = $opts{u};         
    $Opt_AdminUID = $TRUE;              # -u flag specified
}

if (defined $opts{Q}) {                 # -Q for quorum group name
    $q_type = $opts{Q};         
    # turn quorum type into a number
    $q_type = check_quorum_type($q_type); 
    $Opt_QuorumType = $TRUE;            # -Q flag specified
}
 
if (defined $opts{G}) {                 # -G for quorum group name
    $q_group = $opts{G};         
    $Opt_GroupQ = $TRUE;                # -G flag specified
}

if (defined $opts{m}) {			# -m for thread fanout
    $fanout = $opts{m};
    $Opt_Fanout = $TRUE;		# -m flag specified
}
 
return(0, $hats_port, $hags_port, $cssk_type, $refresh_interval,
       $admin_uid, $file_name, $cluster_name, $q_type, $q_group, 
       @node_names);  # success

}   # end parse_cmd_line


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#--------------------------------------------------------------------#
sub print_usage
{
&printIMsg("IMsgmkrpdomainUsageElg");
}   # end print_usage


#--------------------------------------------------------------------#
# mkrsrcapi_file - function to call the mkrsrc-api command after     #
#   building an input file conataining the resource definition.      #
#   This is called when the command line buffer is not big enough to #
#   handle all of the command input to be processed.                 #
#                                                                    #
# Parameters:                                                        #
#   $cluster_name     input   The cluster name to create.            #
#   $mk_options       input   The optional attributes to set.        #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   Trace             input   Trace call & return of extension.      #
#   Verbose           input   Print newly defined rsrc handle.       #
#--------------------------------------------------------------------#
sub mkrsrcapi_file
{
my ($cluster_name, $mk_options) = @_;
my $rc = 0;
my $mk_cmd = "";
my @cmd_out = ();
my $mk_file = "";
my $mk_time = 0;       
my $mk_pid = $$;       
my $file_error = "";

# create the file name to be used
$mk_time = time();
$mk_file = "/tmp/mkrpdomain_file_input.${mk_pid}.${mk_time}";

# create the text for the file input
$mk_cmd = "${RSCLUSTER}::Name::${cluster_name}${other_opts}\n";

if ($main::Trace) { print STDERR "Creating $mk_file to store resource information.\n";}

if (open (MKFILE, ">$mk_file") ) {

   if (!(print MKFILE $mk_cmd)) {
      # get the error
      $file_error = $!;

      # print error message and exit
      &printEMsg("EMsgmkrpdomainTempFileError",$file_error);

      # try to delete the temp file in case it was created
      @cmd_out = `/bin/rm $mk_file 2>&1`;
      exit(CRM_CLI_USER_ERROR);
   }

   if (!(close(MKFILE))) {
      # get the error
      $file_error = $!;

      # print error message and exit
      &printEMsg("EMsgmkrpdomainTempFileError",$file_error);

      # try to delete the temp file in case it was created
      @cmd_out = `/bin/rm $mk_file 2>&1`;
      exit(CRM_CLI_USER_ERROR);
   }
}

# process error from open
else {
   # get the error
   $file_error = $!;

   # print error message and exit
   &printEMsg("EMsgmkrpdomainTempFileError",$file_error);

   # try to delete the temp file in case it was created
   @cmd_out = `/bin/rm $mk_file 2>&1`;
   exit(CRM_CLI_USER_ERROR);
}

if ($main::Trace) { print STDERR "Calling mkrsrc-api:\n";
   print STDERR "mkrsrc-api parameters:";
   print STDERR "$mk_cmd\n";
}

# call mkrsrc-api. -F causes the input file to be deleted
@mk_out = `$CTBINDIR/mkrsrc-api -F $mk_file 2>&1`;

# capture the return code from mkrsrc-api
$rc = $?;
$rc = process_exit_code($rc);

if ($main::Trace) { print STDERR "mkrsrc-api results:\n";
   print STDERR "mkrsrc-api returned $rc \n";
   print STDERR "@mk_out";
}

# show any errors if there was a bad rc
if ($rc != 0) {
   process_api_error("::",$rc,@mk_out);
}

# delete the temp file, just in case
@cmd_out = `/bin/rm $mk_file 2>&1`;

return $rc;
}   # end mkrsrcapi_file


#--------------------------------------------------------------------#
# mkrsrcapi_cmdline - function to call the mkrsrc-api command after  #
#   building a command string to pass to the command.                #
#                                                                    #
# Parameters:                                                        #
#   $cluster_name     input   The cluster name to create.            #
#   $mk_options       input   The optional attributes to set.        #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   Trace             input   Trace call & return of extension.      #
#   Verbose           input   Print newly defined rsrc handle.       #
#--------------------------------------------------------------------#
sub mkrsrcapi_cmdline
{
my ($cluster_name, $mk_options) = @_;
my $rc = 0;
my @mk_out = ();

if ($main::Trace) { print STDERR "Calling mkrsrc-api:\n";}

@mk_out=`$CTBINDIR/mkrsrc-api "${RSCLUSTER}::Name::${cluster_name}${other_opts}" 2>&1`;

# capture the return code from mkrsrc-api
$rc = $?;
$rc = process_exit_code($rc);

if ($main::Trace) { print STDERR "mkrsrc-api results:\n";
   print STDERR "mkrsrc-api returned $rc \n";
   print STDERR "@mk_out";
}

# show any errors if there was a bad rc
if ($rc != 0) {
   process_api_error("::",$rc,@mk_out);
}

return $rc;
}   # end mkrsrcapi_cmdline

