#!/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 = "@(#)86 1.27 src/rsct/rm/ConfigRM/cli/bin/startrpnode.perl, configrmcli, rsct_rady, rady2035a 7/13/18 03:24:21" ###################################################################### # # # Module: startrpnode # # # # Purpose: # # startrpnode - brings a node online to an RSCT peer domain. # # # # Syntax: # # startrpnode [-h] [-w [-s Seconds]] [-TV] Node_name [Node_name # # ...] # # # # startrpnode [-h] -f File | -F file [-w [-s Seconds]] [-TV] # # # # Flags: # # -h Help. Writes the command's usage statement to standard # # output. # # -f File The file containing the nodes names to be brought online # # to the peer domain. The node names are defined as # # 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. # # -w Wait. When -w is specified, the command will wait for # # the all of the specified nodes to be online before the # # command completes. Use the -s flag to specify how long # # the command waits. # # -s Seconds. Used with the -w flag to specify how long in seconds# # the command is to wait for all of the specified nodes to # # be online. If the waiting exceeds the number of seconds, # # the command returns, but the online operation continues. # # The default is 300 seconds (5 minutes). Use 0 to specify# # that the command should not return until all of the # # specified nodes are online (no timeout on waiting). # # -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: # # Node_name The name of the node to be brought online to the # # peer domain. The node name is the peer domain node # # name of the node. The peer domain node names can be # # displayed using the lsrpnode command. # # # # Description: # # The startrpnode command brings an offline node online to a # # peer domain. The peer domain is determined by the online peer # # domain of where the command is run. The command must be run # # from a node that is online to the desired peer domain # # # # The node being brought online must already have been defined to # # be in this peer domain using the mkrpdomain or addrpnode command.# # The node must not be online to any other peer domain. # # # # 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 bring the node nodeB online to the peer domain ApplDomain, # # when nodeA is defined and online to ApplDomain, nodeB is # # reachable from nodeA, and nodeB is not online to ApplDomain # # or any other peer domain, run the following comand from # # nodeA: # # startrpnode nodeB # # # # Man Page: # # For the most current detailed description of this command see # # the startrpnode man page in /opt/rsct/man. # # # #--------------------------------------------------------------------# # Inputs: # # /opt/rsct/msgmaps/configrmcli.startrpnode.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: Check node list to see if ok to start # # 011219 JAC 78807: Don't resolve node names or check if in cluster# # 020202 JAC 79963: weed out startrsrc error messages. # # 020207 JAC 80121: Make printing of c-api results a trace msg. # # 020422 JAC 82248: Rename startclnode to startrpnode. # # 020428 JAC 82316: Call process_exit_code to check $rc. # # 020503 JAC 82564: Set peer domain scope before calling startrsrc.# # 020530 JAC 82589: Use startrsrc-api instead of startrsrc. # # 020711 JAC 84621: Use NodeNameList instead of Name in startrsrc. # # 040319 JAC 97465: Add -f/-F flags for file input for node names. # # 040406 JAC 106712: Update usage for file options. # # 050127 JAC 111917: Use runact-api instead of startrsrc. # # 050406 JAC 119510: Add rc when calling process_api_error. # # 050506 JAC 119921: Fix verbose message when node list not known. # # 051218 JAC 131665: Add -w/-s to make command synchronous. # # 100604 NG 165141: Add check for CAA domain type # ###################################################################### #--------------------------------------------------------------------# # General Program Flow/Logic: # # # # 1. Parse command line flags and operands. # # 2. Print usage if -h specified # # 3. Resolve the name of the node the command will run on and make # # sure that it's online in the cluster. # # 4. Resolve the target node names and make sure they are in the # # cluster and not already online # # 5. Call RMC command startrsrc. Also pass along -VT if necessary. # # 6. 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); 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 check_node_state check_for_nodes process_api_error process_exit_code get_nodes_nums_from_file get_opstate_by_name get_opstate_by_name_rc get_domain_type); use CRM_cli_include qw($TRUE $FALSE $RMC_CLI_USER_ERROR $RMC_OPSTATE_ONLINE $RSNODE $PEER_DOMAIN_SCOPE $CTBINDIR $CTDIR $DELIMITER); #--------------------------------------------------------------------# # Global Variables # #--------------------------------------------------------------------# $Trace = $FALSE; # default - trace off $Verbose = $FALSE; # default - verbose turned off $Opt_File_Input = $FALSE; # default - no file $Opt_Synchronous = $FALSE; # default - no waiting $PROGNAME = "startrpnode"; # 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 @node_names = (); # nodes to be started my %node_opstates = (); # nodes in cluster my %node_opstates_new = (); # nodes in cluster refreshed my @node_info = (); # nodes in cluster my $resolved_node_names = ""; # resolved nodelist my $unresolved_node_names = ""; # unresolved nodelist my @node_names_to_start = (); # node names to start my $one_node = ""; # one from nodelist my $node_online = $FALSE; # boolean my $in_list = ""; # reference to array my $not_in_list = ""; # reference to array my @cmd_out = (); # output from startrsrc my @nnodes = (); # number of nodes 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_numbers = (); # nodes in cluster my $start_nodes = ""; # string of list of nodes my $comma_needed = $FALSE; # add comma to list? my $Use_startrsrc = $FALSE; # is env var set to use old way my $wait_timeout = 300; # wait timeout value my $wait_poll_int = 30; # wait polling interval my $TIMED_OUT = $FALSE; # check timeout my $NODES_ONLINE = $FALSE; # check nodes state my $passopts = ""; # TV options to pass to RMC CLI my $other_opts = ""; # parameters to pass to RMC CLI my $delimiter = "#:#"; $DELIMITER = $delimiter; # override so utils don't choke on IPv6 "::" #--------------------------------------------------------------------# # Main Code # #--------------------------------------------------------------------# my $rc = 0; my $state_rc = 0; my $config_rc = 0; # set peer domain scope $ENV{CT_MANAGEMENT_SCOPE} = $PEER_DOMAIN_SCOPE; # parse the command line, exit if there are errors ($rc, $file_name, $wait_timeout, @node_names) = &parse_cmd_line; ($rc == 0) || error_exit($rc); if ($Verbose) { printIMsg("IMsgstartrpnodeStarted"); } if ($Trace) { $passopts = $passopts." -T"; } if ($Verbose) { $passopts = $passopts." -V"; } # if CT_CONFIGRMCLI_METHOD is set, use startrsrc-api (old way) if (defined $ENV{CT_CONFIGRMCLI_METHOD}) { $Use_startrsrc = $TRUE; } # set the wait polling interval in case it's used if (defined $ENV{CT_CONFIGRMCLI_POLL_INTERVAL}) { if ( ($ENV{CT_CONFIGRMCLI_POLL_INTERVAL} =~ /^[0-9]+$/) && ($ENV{CT_CONFIGRMCLI_POLL_INTERVAL} >=1) ) { $wait_poll_int = $ENV{CT_CONFIGRMCLI_POLL_INTERVAL}; } } # get the nodes opstate info %node_opstates = get_opstate_by_name($RSNODE); # make sure there are nodes in the cluster @nnodes = keys %node_opstates; if ($#nnodes <0) { printCEMsg("EMsgConfigRMcliNoCluster"); 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; } if ($Verbose) { printIMsg("IMsgstartrpnodeNodeList"); foreach $one_node (@node_names) { print(" ", $one_node); } print("\n"); } # make sure the target nodes are in the cluster ($in_list, $not_in_list) = check_for_nodes(\@node_names, \%node_opstates); # for nodes not in the list (not in the cluster), print error message foreach $one_node (@$not_in_list) { printEMsg("EMsgstartrpnodeNotInCluster",$one_node); $config_rc = CRM_CLI_USER_ERROR; } # for nodes in the list (in the cluster), # make sure they're not online and then add to list for starting foreach $one_node (@$in_list) { $node_online = check_node_state($one_node,$RMC_OPSTATE_ONLINE, %node_opstates); if (!$node_online) { # printEMsg("EMsgstartrpnodeAlreadyStarted",$one_node); # $config_rc = CRM_CLI_USER_ERROR; # } # # it's offline so add to list to start # else { push (@node_names_to_start, $one_node); } } # Quit here for CAA domain type if(get_domain_type()) { #printCEMsg("EMsgConfigRMCmdNotSupported"); exit (CRM_CLI_SUCCESS); } # decide whether old way or new way # if CT_CONFIGRMCLI_METHOD is set, do old way if ($Use_startrsrc) { # for each node to start, call startrsrc-api foreach $one_node (@node_names_to_start) { if ($Trace) { print STDERR "$PROGNAME: calling startrsrc-api\n";} #@cmd_out = `$CTBINDIR/startrsrc $passopts -s "Name==\\\"$one_node\\\"" $RSNODE 2>&1`; #@cmd_out=`$CTBINDIR/startrsrc-api -s ${RSNODE}::Name==\\\"${one_node}\\\" 2>&1`; @cmd_out=`$CTBINDIR/startrsrc-api -I"$delimiter" -s "${RSNODE}${delimiter}NodeNameList|<{\\\"${one_node}\\\"}" 2>&1`; # capture the return code from startrsrc-api $rc = $?; $rc = process_exit_code($rc); if ($Trace) { print STDERR "startrsrc-api results:\n"; print STDERR "@cmd_out";} if ($Trace) { print STDERR "$PROGNAME: startrsrc-api returned $rc\n";} # show any errors if there was a bad rc if ($rc != 0) { process_api_error($delimiter,$rc,@cmd_out); } # save rc as ConfigRM CLI user error if it's an RMC CLI user error if ($rc == $RMC_CLI_USER_ERROR) { $config_rc = CRM_CLI_USER_ERROR; } # if startrsrc failed, print RMC error message and save rc if (($rc != 0) && ($rc != $RMC_CLI_USER_ERROR)) { #printCEMsg("EMsgConfigRMcliUnExpectRMCrc",$rc); $config_rc = CRM_CLI_RMC_ERROR; } } } # else use new way else { # build a string containing the list of node names to start $start_nodes = ""; $comma_needed = $FALSE; foreach $one_node (@node_names_to_start) { if ( $comma_needed ) { $start_nodes .= "," . $one_node; } else { $start_nodes .= $one_node; $comma_needed = $TRUE; } } # call runact-api to start the nodes if there are nodes to start if ($#node_names_to_start >= 0) { # Defect 161752 my $cmd = "$CTBINDIR/runact-api -I\"$delimiter\" -c ${RSNODE}${delimiter}${delimiter}StartMultipleNodes${delimiter}NodeNames${delimiter}"."\"{${start_nodes}}\""; if ($Trace) { print STDERR "$PROGNAME: calling runact-api\n";} if ($Trace) { print STDERR "$PROGNAME: $cmd runact-api\n";} @cmd_out=`$cmd 2>&1`; #@cmd_out=`$CTBINDIR/runact-api -I"$delimiter" -c "${RSNODE}${delimiter}${delimiter}StartMultipleNodes${delimiter}NodeNames${delimiter}{${start_nodes}}" 2>&1`; # capture the return code from runact-api $rc = $?; $rc = process_exit_code($rc); if ($Trace) { print STDERR "runact-api results:\n"; print STDERR "@cmd_out"; print STDERR "$PROGNAME: runact-api returned $rc\n";} # show any errors if there was a bad rc if ($rc != 0) { process_api_error($delimiter,$rc,@cmd_out); } # save rc as ConfigRM CLI user error if it's an RMC CLI user error if ($rc == $RMC_CLI_USER_ERROR) { $config_rc = CRM_CLI_USER_ERROR; } # if runact-api failed, print RMC error message and save rc if (($rc != 0) && ($rc != $RMC_CLI_USER_ERROR)) { # printCEMsg("EMsgConfigRMcliUnExpectRMCrc",$rc); $config_rc = CRM_CLI_RMC_ERROR; } } } # if wait until started selected if ($Opt_Synchronous) { # use $i to check for timeout exceeded $i = 0; $TIMED_OUT = $FALSE; $NODES_ONLINE = $FALSE; # check opstate until all nodes online or timeout exceeded while ( (!$NODES_ONLINE) && (!$TIMED_OUT) ) { sleep($wait_poll_int); $i = $i + $wait_poll_int; # get new opstates ($state_rc, %node_opstates_new) = get_opstate_by_name_rc($RSNODE); if ($state_rc == 0) { %node_opstates = %node_opstates_new; } # see if everybody's online yet $NODES_ONLINE = $TRUE; foreach $one_node (@node_names_to_start) { $node_online = check_node_state($one_node,$RMC_OPSTATE_ONLINE, %node_opstates); if (!$node_online) { $NODES_ONLINE = $FALSE; } } # check to see if we've timed out if ( (!$NODES_ONLINE) && ($i > $wait_timeout) && ($wait_timeout != 0) ){ printCEMsg("EMsgConfigRMcliWaitTimedOut"); $config_rc = CRM_CLI_ERROR; $TIMED_OUT = $TRUE; } } } if ($Verbose) { printIMsg("IMsgstartrpnodeEnded"); } 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. # # $wait_timeout Wait timeout value. # # @node_names Node names to be started. # # # # Global Variables Modified: # # $Verbose output True (-V) turn Verbose mode on. # # $Trace output True (-T) turn Trace mode on. # # $Opt_File_Input output True (-f|-F) file name specified # # $Opt_Synchronous output True (-w) Wait. # #--------------------------------------------------------------------# sub parse_cmd_line { my(@original_argv) = @ARGV; my @node_names = (); # nodes to be started my $file_name = ""; # file name my $wait_timeout = 300; # wait timeout value my %opts = (); # Process the command line... if (!&getopts('hf:F:ws: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; } if (defined $opts{w}) { # -w for wait $Opt_Synchronous = $TRUE; # -w flag specified } if (defined $opts{s}) { # -s for wait timeout # error if -w is not if (!$Opt_Synchronous) { printCEMsg("EMsgConfigRMcliUnexpectFlag","-s","-w"); &print_usage; return CRM_CLI_BAD_FLAG; } #check the timeout value if ( ($opts{s} =~ /^[0-9]+$/) && ($opts{s} >=0)) { $wait_timeout = $opts{s}; } else { printEMsg("EMsgstartrpnodeInvTimeoutSeconds","$opts{s}"); &print_usage; return CRM_CLI_BAD_FLAG; } } # Get the arguments... # Operands: 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; } } return(0, $file_name, $wait_timeout, @node_names); # success } # end parse_cmd_line #--------------------------------------------------------------------# # print_usage : print the usage statement (syntax) to stdout. # #--------------------------------------------------------------------# sub print_usage { &printIMsg("IMsgstartrpnodeUsageW"); } # end print_usage