#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2001,2019 
# 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 
# sccsid = "@(#)82   1.67   src/rsct/rm/ConfigRM/cli/bin/mkrpdomain.perl, configrmcli, rsct_rady, rady2035a 11/12/15 16:40:52"
######################################################################
#                                                                    #
# 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] [-6]                 #
#              [-p 0 | -p 1]                                         #
#              [-S "none" | -S "nist_sp800_131a" ] [-TV] PeerDomain  #
#              Node_name[@Host_name] [Node_name[@Host_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] [-6] [-p 0 | -p 1]   #
#              [-S "none" | -S "nist_sp800_131a" ]                   #
#              -f File|-F File [-TV] PeerDomain                      #
#                                                                    #
#   mkrpdomain [-h] -C 0|1 -R RepositoryDisk[hdiskN,...]             #
#              [-D sharedDisk[hdiskN,...] [-TV]                      #
#              [-p 0 | -p 1] [-S 0 | -S 1] PeerDomain                #
#              Node_name[@Host_name] [Node_name[@Host_name] ...]     #
#                                                                    #
# 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.       #
#   -C      Specify the domain type:                                 #
#               0     Traditional peer domain                        #
#               1     Cluster Aware AIX (CAA)                        # 
#   -D sharedDisk   The CAA storage device shared between cluster    #
#           nodes.                                                   #
#   -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.                                     #
#   -6      allows IPv6 addresses to participate in peer domain      #
#           internal operations and heartbeating even though the     #
#           nodes in the peer domain use IPv4 addresses.  If IPv6    #
#           addresses are configured and this flag is not specified, #
#           the IPv6 addresses will not be permitted to participate  #
#           in peer domain internal operations or heartbeating.      #
#   -R RepositoryDisk  The CAA storage repository                    #
#   -p NamePolicy   The NamePolicy determines the synchronization    #
#           across nodename & hostname PeerNode attributes, this is  #
#           optional.                                                #
#                  0   ManualNameUpdate, This is the default in a    #
#                      traditional peer domain.                      #
#                  1   AutoHostNameSync, This is the default in the  #
#                      CAA-environment.                              #
#   -S SecurityMode Specifies Nist Compliance Mode of a PeerDomain   #
#                    read-only attribute of IBM.PeerDomain, this is  #
#                    optional.                                       #
#                  0   Legacy Mode, this is the default value        #
#                  1   NIST Compliance mode, i.e NIST_SP800_131A     # 
#   -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 can be made up of the characters A-Z, a-z,  #
#               0-9, . (period), _ (underscore), and - (hyphen).     #
#               The name cannot begin with a hyphen. The name must   #
#               not be IW, . (period), or .. (two periods).          #
#   Node_name[@Host_name]   The node to include in this peer domain  #
#               definition. The node name (the Host_name, if there   #
#               is any input) 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.                #
#               The "@Host_name" input is applicable for non-CAA     #
#               domain not applicable for CAA.                       #
#               Node_name will be populated in nodename attribute.   #
#               Host_name will be populated in hostname attribute,   #
#               if any, otherwise populated initially with           #
#               Node_name.                                           #
#                                                                    #
# 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 (non-CAA) consisting of nodeA, nodeB, #
#      and nodeC,with hostnames hostA, hostB, and hostC respectively,#
#      with the peer domain name ApplDomain, run the following       #
#      command on nodeA, nodeB, or NodeC:                            #
#      mkrpdomain ApplDomain nodeA[@hostA] nodeB[@hostB]             #
#      nodeC[@hostC]                                                 #
#                                                                    #
#   4. 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 /opt/rsct/man.                   #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/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.    #
#   071105 JAC 146610: add tiebreaker support, -B in file.           #
#   071221 JAC 147708: allow - (hyphen) in name and check for . and..#
#   080201 JAC 149153: correct the pattern match for prev defect.    #
#   080519 JAC 151136: add -6 flag for IPv6.                         #
######################################################################

#--------------------------------------------------------------------#
# 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 "/opt/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
                     form_quorum_attribute
                     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

$ClusterType_PeerDomain = 0;		# Traditional PeerDomain
$ClusterType_CAA = 1;			# ClusterType: CAA
$ClusterType_CAAInt = 1;		# Processing go through ConfigRM
$ClusterType_CAAExt = 2;		# Processing in mkrpdomain

$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
$Opt_ShowIPv6 = $FALSE;                 # default - no IPv6 usage
$Opt_ClusterType = $ClusterType_PeerDomain;                      # default - no cluster aware AIX 
$Opt_CAADisk = $FALSE;                  # default - no CAA share disk
$Opt_CAARepos = $FALSE;                 # default - no CAA repository disk
$Opt_DomainType_Flag = FALSE;           # default - domain flag is not specified
$Opt_Namepolicy = $FALSE;               # default - as per cluster type
                                        #     0       ManualNameUpdate, This is the default in a traditional peer domain.
                                        #     1       AutoHostNameSync, This is the default in the CAA-environment.
$Opt_SecurityMode = $FALSE;             # 

$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 @node_quorum_flags = ();             # Quorum array
my @node_gsgl_flags = ();               # IsPreferredGSGLArray
my @node_tiebreaker_flags = ();         # Tiebreaker array
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_quorum_flags_file = "";        # reference to quorun array
my $node_gsgl_flags_file = "";          # reference to IsPreferredGSGLArray
my $node_tiebreaker_flags_file = "";    # reference to tiebreaker array
my $node_quorum_arg = "";               # reference to quorum arg array
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 $caa_flag = "";                      # Domain type flag for CAA
my $caa_disk = "";                      # CAA shared disk
my $caa_repos = "";                     # CAA repository disk
my $name_policy = 0;                    # Name policy
my $name_policy_undef = -1;             # Name policy undefined value
my $node_names_list = "";               # Node name list
my $host_names_list = "";               # Host name list
my @nodenames_list = ();                # Node names list
my @nodenames = ();
my @hostnames = ();
my $tmp_node_name = "";
my $tmp_host_name = "";
my $last_host_name = "";
my $security_mode = "none";                  # SecurityMode[Nist Compliance mode]

my $passopts = "";                      # TV options to pass to RMC CLI
my $other_opts = "";                    # parameters to pass to RMC CLI
my $delimiter = "#:#";
#--------------------------------------------------------------------#
# 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, 
 $caa_disk, $caa_repos, $name_policy,$security_mode, @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 is not . or ..
if ( ($cluster_name eq ".") || ($cluster_name eq "..") ) {
         printEMsg("EMsgmkrpdomainNameDots");
         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), - (hyphen)
# hyphen not allowed 1st but it looks like a flag on input so test really never happens
if ($cluster_name !~ /^[A-Za-z0-9._]+[A-Za-z0-9._-]*$/) {
         printEMsg("EMsgmkrpdomainNameIsBad");
         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, $node_quorum_flags_file,
                  $node_gsgl_flags_file, $node_tiebreaker_flags_file) 
            = get_nodes_nums_from_file($file_name);

   # copy to other array
   @node_names = @$node_names_file;
   @node_numbers = @$node_nums_file;
   @node_quorum_flags = @$node_quorum_flags_file;
   @node_tiebreaker_flags = @$node_tiebreaker_flags_file;
   @node_gsgl_flags = @$node_gsgl_flags_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."${delimiter}TSPort${delimiter}$hats_port";
}

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

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

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

# pass in the domain type, if specified
if ($Opt_DomainType_Flag == $TRUE) {
    if ($Opt_ClusterType== $ClusterType_PeerDomain) {    #Domain Type is traditional RPD
	    $other_opts = $other_opts."${delimiter}DomainType${delimiter}${ClusterType_PeerDomain}";
    }
    elsif($Opt_ClusterType == $ClusterType_CAAInt || $Opt_ClusterType == $ClusterType_CAAExt ) {
         #Domain Type is CAA 
        $other_opts = $other_opts."${delimiter}DomainType${delimiter}${ClusterType_CAA}";
    }
}

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

# 144366 , move this block of code down to after Fanout
# pass in quorum group, if specified
#if ($Opt_GroupQ) {                    # -G used for quorum group name
#   $other_opts = $other_opts."${delimiter}QuorumGroupName${delimiter}$q_group";
#}

# Hostname change support.
# User has the flexibility to provide node name and corresponding hostname, like nodename[@hostname]
# Hostname would be considered for resolving nodename otherwise node name will be used.
$comma = "";
foreach $one_node (@node_names) {
    $tmp_node_name = "";
    $tmp_host_name = "";

    ($tmp_node_name, $tmp_host_name) = split /@/, $one_node;

    push (@nodenames, $tmp_node_name);

    $last_host_name = $tmp_host_name;

    if ($tmp_host_name eq "") {
        # Consider nodename as there is no Hostname
        push (@nodenames_list, $tmp_node_name);
        $host_names_list = $host_names_list.$comma."";
    }
    else {
        # Consider hostname as there is input for corresponding nodename
        push (@nodenames_list, $tmp_host_name);
        push (@hostnames, $tmp_host_name);
        $host_names_list = $host_names_list.$comma.$tmp_host_name;
    }
    $comma = ",";
}

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

# 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
foreach $one_node (@nodenames, @hostnames) {
   if ((! $Opt_ShowIPv6) && ($one_node =~ /:/)) {
      printEMsg("EMsgmkrpdomainIPv6AddressNotPermitted",$one_node);
      exit CRM_CLI_USER_ERROR; 
   }
}

$comma = "";
foreach $one_node (@nodenames) {
    $node_names_list = $node_names_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 = ",";
}

# setup the nodelist
$other_opts = $other_opts."${delimiter}${delimiter}NodeNames${delimiter}"."{$node_names_list}";

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

# setup the IsQuorumNodeArray list
#if ( $#node_quorum_flags >= 0 ) {
#   $other_opts = $other_opts . "${delimiter}IsQuorumNodeArray${delimiter}" . '{' . join( ',', @node_quorum_flags ) . '}';
#}

# setup the IsQuorumNodeArray cmd arg from quorum and tiebreaker
$node_quorum_arg = form_quorum_attribute(\@node_quorum_flags, \@node_tiebreaker_flags);
if ( $#$node_quorum_arg >= 0 ) {
   $other_opts = $other_opts . "${delimiter}IsQuorumNodeArray${delimiter}" . '{' . join( ',', @$node_quorum_arg ) . '}';
}

# setup the IsPreferredGSGLArray list
if ( $#node_gsgl_flags >= 0 ) {
   $other_opts = $other_opts . "${delimiter}IsPreferredGSGLArray${delimiter}" . '{' . join( ',', @node_gsgl_flags ) . '}';
}
# continue on error specified?
if ($Opt_Continue) {
   $other_opts = $other_opts."${delimiter}ContinueIfError${delimiter}1";
}
#93122 - comment out specifying the default command argument
#else {
#   $other_opts = $other_opts."${delimiter}ContinueIfError${delimiter}0";
#}

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

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

# pass in CSSK type if specified
if ($Opt_CSSKType) {                    # -k used for key type
   $other_opts = $other_opts."${delimiter}CSSKType${delimiter}$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."${delimiter}CSSKRefreshInterval${delimiter}$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."${delimiter}CSSKRefreshInterval${delimiter}$translated_interval";
}

# pass in to show IPv6 addresses, if specified   151136
if ($Opt_ShowIPv6) {          # -6 used to allow IPv6 for RPD
   $other_opts = $other_opts."${delimiter}EnableIPv6Support${delimiter}1";
}

# NamePolicy need to be passed which is required to maintain
# the sync across nodename and hostname, if specified.
if (!$Opt_Namepolicy) {
    $name_policy = $name_policy_undef;
}
$other_opts = $other_opts."${delimiter}NamePolicy${delimiter}$name_policy";

# Pass hostnames list if any.
#
# 190520:
# If last hostname is found to be empty in $host_names_list,
# append an additional "," to the end of $host_names_list for
# calculating proper element count for hostnames list in mkrsrc-api
$comma = ",";
if ($hostnames[0] ne "") {
    if ($last_host_name eq "") {
        $host_names_list = $host_names_list.$comma;
    }

    $other_opts = $other_opts."${delimiter}HostNames${delimiter}"."{$host_names_list}";
}

# Prepare to call either mkcluster or mkrsrc-api depending on domain type
if ($Opt_ClusterType == $ClusterType_CAAExt) {
  $rc = &MakeCAACluster($cluster_name, $caa_disk, $caa_repos, @node_names);
}
elsif ($Opt_ClusterType == $ClusterType_CAAInt) {
        if ($Opt_CAADisk) {
           $other_opts = $other_opts."${delimiter}CAAClusterDisk${delimiter}$caa_disk";
        }
        if ($Opt_CAARepos) {
           $other_opts = $other_opts."${delimiter}CAAReposDisk${delimiter}$caa_repos";
        }
}


# SecurityMode , push this to other_opts if specified

# SecurityMode specified for creating cluster in NIST compliance mode
if ($Opt_SecurityMode) {          # SecurityMode specified for creating cluster in NIST compliance mode
    $other_opts = $other_opts."${delimiter}SecurityMode${delimiter}$security_mode";
}


# 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                       #
#   $name_policy             Name policy                             #
#                                                                    #
# 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          #
#   $Opt_ShowIPv6      output   True (-6) IPv6 allowed on.           #
#   $Opt_ClusterType   output   True (-C) Domain Type is CAA         #
#   $Opt_Namepolicy    output   True (-p) Name policy specified,     #
#                                         don't consider default value
#   $Opt_SecurityMode  output   True (-S) SecurityMode specified     #
#--------------------------------------------------------------------#
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 $name_policy = 0;                    # Name policy
my $security_mode = "none";             # Security Mode ["none", "nist_sp800_131a"]
my %opts = ();

# Process the command line...
if (!&getopts('C:ht:g:G:Q:k:r:R:D:cu:f:F:m:p:S:VT6', \%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
}

if (defined $opts{6}) {                 # -6 to allow IPv6 in RPDr
    $Opt_ShowIPv6 = $TRUE;              # -6 flag specified
}

if (defined $opts{C}) {                 # -C to specify the cluster type
    $caa_flag = $opts{C};
    $Opt_DomainType_Flag = $TRUE;       # boolean domain flag was specified
    if(($caa_flag eq "") || ($caa_flag =~/-/)) {
        printCEMsg("EMsgConfigRMcliMissingRequiredFlagOperand", "-C");
        &print_usage;
        return CRM_CLI_BAD_OPERAND;
    }
    else {
        if (($caa_flag == $ClusterType_CAAExt ) ||
            ($caa_flag == $ClusterType_CAAInt) ||
            ($caa_flag == $ClusterType_PeerDomain)) {
            $Opt_ClusterType = $caa_flag;
        }
        else {
            printCEMsg("EMsgConfigRMcliImproperUsageOperand", $caa_flag);
            &print_usage;
            return CRM_CLI_BAD_OPERAND;
        }
    }
}
# If -C command option and CT_CAA_CLUSTER_TYPE both specified, command option will be used
# All need to be specified in same way
# if CT_CAA_CLUSTER_TYPE=1 is not specified, CT_CAA_REPOSITORY and CT_CAA_SHARED_DISK will be ignored
# if CT_CAA_CLUSTER_TYPE=1 is specified, CT_CAA_REPOSITORY should be specified
elsif (defined $ENV{CT_CAA_CLUSTER_TYPE}) {
    $caa_flag = $ENV{CT_CAA_CLUSTER_TYPE};
    if($caa_flag == $ClusterType_CAAInt) {
        $Opt_ClusterType = $caa_flag;
        if(defined $ENV{CT_CAA_SHARED_DISK}) {
            $caa_disk = $ENV{CT_CAA_SHARED_DISK};
            $Opt_CAADisk = $TRUE;
        }
        if(defined $ENV{CT_CAA_REPOSITORY}) {
            $caa_repos = $ENV{CT_CAA_REPOSITORY};
            $Opt_CAARepos = $TRUE;
        }else {
            # error - TBD
            return CRM_CLI_BAD_OPERAND;
        }
    }
}

# fail if CAA request and not AIX
if ( $Opt_ClusterType != $ClusterType_PeerDomain ) {
	@sysname=`uname -s`;
	if ( $sysname[0] !~ /AIX/ ) {
		printEMsg( "EMsgmkrpdomainCAANotSup" );
		&print_usage;
		return CRM_CLI_BAD_OPERAND;
	}
}

if (defined $opts{D}) {                  # -D to specify cluster shared Disks
    $caa_disk = $opts{D};
    $Opt_CAADisk = $TRUE;
    if(($caa_disk eq "") || ($caa_disk =~/-/)) {
        printCEMsg("EMsgConfigRMcliMissingRequiredFlagOperand", "-D");
        &print_usage;
        return CRM_CLI_BAD_OPERAND;
    }
    if($Opt_DomainType_Flag==0) {
        printEMsg("EMsgmkrpdomainRNeedsCR");   #must specify -C and -R for CAA
        &print_usage;
        return ERRM_CLI_BAD_FLAG;
    }
}

if (defined $opts{R}) {                   # -R to specify cluster repository disk
    $caa_repos = $opts{R};
    $Opt_CAARepos = $TRUE;
    if(($caa_repos eq "") || ($caa_repos =~/-/)) {
        printCEMsg("EMsgConfigRMcliMissingRequiredFlagOperand", "-R");
        &print_usage;
        return CRM_CLI_BAD_OPERAND;
    }
    if($Opt_DomainType_Flag==0) {
        printEMsg("EMsgmkrpdomainRNeedsC"); #must specify -C
        &print_usage;
        return ERRM_CLI_BAD_FLAG;
    }
}
else {                                    # -R is required when the -C flag is used
    if($Opt_DomainType_Flag==$TRUE && $caa_flag != 0) {
        printEMsg("EMsgmkrpdomainC1NeedsR");
        &print_usage;
        return CRM_CLI_BAD_FLAG;
    }
} 

if (defined $opts{p}) {                   # -p is required to specify name policy
    $name_policy = $opts{p};
    $Opt_Namepolicy = $TRUE;

    if (($name_policy eq "") || ($name_policy =~/-/)) {
        printCEMsg("EMsgConfigRMcliMissingRequiredFlagOperand", "-p");
        &print_usage;
        return CRM_CLI_BAD_OPERAND;
    }
}

if($Opt_ClusterType==$ClusterType_PeerDomain) {
    if($Opt_CAARepos==$TRUE){
      printCEMsg("EMsgConfigRMcliImproperUsageCombination", "-C 0","-R");
      &print_usage;
      return CRM_CLI_BAD_OPERAND;
   }
   elsif($Opt_CAADisk==$TRUE) {
       printCEMsg("EMsgConfigRMcliImproperUsageCombination", "-C 0","-D");
        &print_usage;
        return CRM_CLI_BAD_OPERAND;
   }
}

if (defined $opts{S}) {                   # -S is required to specify SecurityMode[Nist Compliance mode] 
    $security_mode = $opts{S};
    $Opt_SecurityMode = $TRUE;

    if (($security_mode eq "") || ($security_mode =~/-/)) {
        printCEMsg("EMsgConfigRMcliMissingRequiredFlagOperand", "-S");
        &print_usage;
        return CRM_CLI_BAD_OPERAND;
    }
}

if (($Opt_SecurityMode) && ($Opt_ClusterType == $ClusterType_CAAExt || $Opt_ClusterType == $ClusterType_CAAInt)) {          
            printCEMsg("EMsgConfigRMcliImproperUsageCombination", "-C", "-S");
            &print_usage;
            return CRM_CLI_BAD_FLAG;
}
return(0, $hats_port, $hags_port, $cssk_type, $refresh_interval,
       $admin_uid, $file_name, $cluster_name, $q_type, $q_group, 
       $caa_disk, $caa_repos, $name_policy, $security_mode, @node_names);  # success

}   # end parse_cmd_line


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#--------------------------------------------------------------------#
sub print_usage
{
	@sysname=`uname -s`;
	if ( $sysname[0] =~ /AIX/ ) {
		&printIMsg("IMsgmkrpdomainUsageIpv6CAA");
	} else {
		&printIMsg("IMsgmkrpdomainUsageIpv6");
	}
}   # 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 $mytmpdir = "";
my $cttmpdir_exit = 0;
my $mk_file = "";
my $mk_time = 0;       
my $mk_pid = $$;       
my $file_error = "";

# create the file name to be used
$mk_time = time();
$mytmpdir = `/opt/rsct/bin/cttmpdir`;
chomp $mytmpdir;
$cttmpdir_exit = $?;
if ($cttmpdir_exit != 0) {
    $mytmpdir = "/tmp";
}
$mk_file = "${mytmpdir}/mkrpdomain_file_input.${mk_pid}.${mk_time}";

# create the text for the file input
#$mk_cmd = "${RSCLUSTER}${delimiter}Name${delimiter}${cluster_name}${other_opts}\n";
$mk_cmd = "${RSCLUSTER}${delimiter}Name${delimiter}${cluster_name}${mk_options}\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 -D"$delimiter" -I"$delimiter" -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($delimiter,$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 -D"$delimiter" -I"$delimiter" "${RSCLUSTER}${delimiter}Name${delimiter}${cluster_name}${mk_options}" 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($delimiter,$rc,@mk_out);
}

return $rc;
}   # end mkrsrcapi_cmdline

#--------------------------------------------------------------------#
# MakeCAACluster - makes a command string to pass to CAA mkcluster   #
#  command. Upon exit of this function, the CAA cluster will be      #
#  created, and CAA services started.                                #
#                                                                    # 
# Parameters:                                                        #
#   $cluster_name     input   The cluster name to create.            #
#   @node_names       input   The nodes in the cluster.              #
#   $caa_disk         input   The cluster disk                       #
#   $caa_repos        input   The cluster repository disk            #
#--------------------------------------------------------------------#
sub MakeCAACluster
{
my ($cluster_name, $caa_disk, $caa_repos, @node_names) = @_;
my $rc = 0;
my @mkcl_out = ();
my $caa_nodes="";

#Build a comma separated list of the node names to pass to mkcluster

for ($i = 0; $i <= $#node_names; $i++) {
    if($i==0) { $caa_nodes = $node_names[$i]; 
    }
    else { $caa_nodes="$caa_nodes,$node_names[$i]";
    }
} 

if ($main::Trace) { print STDERR "**Invoking CAA mkcluster command\n"; }

@mkcl_out=`/usr/sbin/mkcluster -n $cluster_name -d $caa_disk -m $caa_nodes -r $caa_repos`;
print "@mkcl_out\n";
$rc = $?;

if($rc != 0) {
    print STDERR "mkrpdomain failed: mkcluster rc = $rc\n"; 
}

$rc = process_exit_code($rc);

exit();
} # end MakeCAACluster