#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2000,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 = "@(#)06 1.50 src/rsct/rmc/cli/bin/runact.perl, rmccli, rsct_rady, rady2035a 11/12/15 16:30:56" ###################################################################### # # # Module: runact # # # # Purpose: # # runact - Run / invokes an action on a resource or resource class.# # # # Syntax: # # runact [-h] -s "Selection_string" [-f Resource_data_file] # # [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_class # # Action [In_Element_0=value In_Element_1=value ...] # # [Rsp_Element...] # # # # runact [-h] -r [-f Resource_data_file] # # [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_handle # # Action [In_Element_0_value In_Element_1_value ...] # # [Rsp_Element...] # # # # runact [-h] -c [-f Resource_data_file] [-n Node_name] # # [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_class # # Action [In_Element_0=value In_Element_1=value ...] # # [Rsp_Element...] # # # # runact [-h] -C Peer_domain_names [-f Resource_data_file] # # [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_class # # Action [In_Element_0=value In_Element_1=value ...] # # [Rsp_Element...] # # # # Flags: # # -h Help. Writes this command's usage statement to stdout. # # -c Class. Invoke the action on the resource class instead # # of on the resource. By default the action is invoked on # # the resource. # # -C Peer_domain_names Class. Invoke the action on the resource # # class instead of on the resource. The class must be a # # globalized class of a peer domain that exists in a # # management domain. Peer_domain_names is a list of one # # or more peer domains on which to run the class action. # # -n Node_name The name of the node on which to run the class # # action. The -n flag is only allowed with the -c flag. # # -f Resource_data_input_file File input. Specifies the name of # # the file which contains resource or resource class # # input elements. For example: # # ResourceAction:: # # element1 = value # # element2 = value # # ... # # - or - # # ResourceClassAction:: # # element1 = value # # element2 = value # # ... # # Use the lsactdef command with the -i flag to generate a # # template for this input file. # # -s "Selection string" Specifies the selection string. All # # selection strings must be enclosed within either double # # or single quotation marks. If the selection string # # contains double quotation marks, enclose the entire # # selection string in single quotation marks. For example: # # -s 'Name == "testing"' # # -s 'Name ?= "test"' # # Only persistent attributes can be listed in a selection # # string. # # -r Resource Handle. Invoke the action on the specific # # resource that matches the specified resource handle. # # -l Long formatted output. Each element is displayed on a # # separate line. This is the default display format. # # -t Tabular formatted output. Each element is displayed # # in a separate column, one response per line. # # -d Delimiter-formatted output. The default delimiter is # # a colon (:). Use the -D flag if you wish to change # # the default delimiter. # # -D Delimiter Delimiter formatted output using the specified # # delimiter. Use this flag to specify something other than # # the default colon (:). An example is when the data to be # # displayed contains colons. Use this flag to specify a # # delimiter of one or more characters. # # -x Exclude header. Suppress header printing. # # -T Trace. Writes the command's trace messages to standard # # error. For your software-service organization use only. # # -V Verbose. Writes this command's verbose messages to # # standard output. # # # # Operands: # # Resource_class The name of the resource class that we want to # # invoke the action against. # # # # Action The name of the action that we want to invoke. # # # # In_Element=value Enter all of the Action input elements and # # values. If the -f flag is specified, In_Element= # # value pair operands should not be entered on the # # command line. There should be one In_Element= # # value pair for each of the defined SD input # # elements for the specified action. # # Run lsactdef -i Resource Action to generate a # # template of the required SD input elements for # # this action. # # # # In_Element Action input element name. # # Run lsactdef -si Resource Action to see the # # action input element names for this Action. # # # # value The value for this action input element, the # # value data type must match the definition of # # this elements data type. # # Run lsactdef -si Resource Action to determine # # the data type. # # # # Response_Element Zero or more of the action response element # # names may be specified. If zero element names # # are specified, all the elements are displayed. # # If one or more element names are specified, only # # those elements and their values are displayed # # in the specified order. # # # # Description: # # The runact command requests the RMC subsystem to run (invoke) # # the specified action on the resource or resource class. # # # # Prior to running runact you should run the lsactdef command # # to determine the action name and action input structured data # # elements that must be specified when invoking an action. # # # # Exit Values: # # 0 MC_CLI_SUCCESS Command completed successfully. # # 1 MC_CLI_RMC_ERROR Command terminated due to an underlying # # RMC error. # # 2 MC_CLI_ERROR Command terminated due to an underlying # # error in the command script. # # 3 MC_CLI_BAD_FLAG Command terminated due to user # # specifying an invalid flag. # # 4 MC_CLI_BAD_OPERAND Command terminated due to user # # specifying a bad operand. # # 5 MC_CLI_USER_ERROR Command terminated due to a user error. # # For example specifying an undefined # # Resource name as the Resource operand. # # 6 MC_CLI_NO_RSRC_FOUND No resources were found that matched # # the specified selection string. # # # # Examples: # # runact -s 'Name == "c175n05"' IBM.Foo TestResourceAction Int32=99# # runact -f IBM.Foo.runact1 -s 'Name == "c175n05"' # # IBM.Foo TestResourceAction # # Note: IBM.Foo.runact1 input file would contain the 2 lines: # # ResourceAction:: # # Int32 = 99 # # runact -s 'Name ?= "*"' IBM.Foo ExecuteCommand # # Command=hostname User=root ExitCode Stdout # # # # Man Page: # # For the most current detailed description of this command see # # the runact man page in /opt/rsct/man. # # # #--------------------------------------------------------------------# # Inputs: # # /opt/rsct/msgmaps/mccli.runact.map - message mapping # # /opt/rsct/msgmaps/mccli.mccil.map - message mapping # # # # Outputs: # # stdout - display of Action output response. # # stderr - any error message. # # # # External Ref: # # Commands: ctdspmsg # # Modules: MC_cli_utils.pm, MC_cli_display_utils.pm, MC_cli_rc.pm # # CT_cli_utils.pm, CT_cli_data_type_utils, # # CT_cli_input_utils.pm, CT_cli_display_utils.pm. # # Extensions: CT::MC, CT::MCerr, CT::CT, CT::CU # # Perl library routines: Getopt::Long # # # # Tab Settings: # # 4 and tabs should be expanded to spaces before saving this file. # # in vi: (:set ts=4 and :%!expand -4) # # # # Change Activity: # # 000517 SAB 64351: Initial design & write. # # 001120 GTM 67900: Add response element, resource handle support. # # 010311 SAB 63852: Prepared for GA. # # 010406 SAB 71892: Support new MC_CLI_NO_RSRC_FOUND return code. # # 011216 JAC 77349: Add -n flag, node_name for class action (1). # # 011217 JAC 79061: Remove using a default for nodenamelist. # # 020925 JAC 87393: Change CT_cli_display_utils to .._displayext.. # # 030123 JAC 91151: Fixes for extensionless version. # # 030205 JAC 91360: Escape inner quotes in select strings. # # 030318 JAC 92966: Fix for no args and bad action name. # # 030402 JAC 93181: Fix for some arg types not passed correctly. # # 030404 JAC 92787: Don't allow -s "" for selection string. # # 030709 JAC 96745: Add delimiter to call to remove_api_error. # # 040111 JAC 100165: Add -C flag for peer domains in DM scope. # # 040116 JAC 103144: Fix for typo introduced by 100165. # # 040407 JAC 105863: Use escape_chars for "\" searches. # # 080521 JAC 150491: Don't assume all actions have input and out. # # 080630 JAC 152000: repeat substitution for binary array output. # # 080723 JAC 151272: make the display multipass if large output. # # 080910 JAC 153444: Fix reseting of variable in display routine. # ###################################################################### #--------------------------------------------------------------------# # General Program Flow/Logic: # # # # A. Parse command line flags and operands, determine which flavor # # of this command we are actually invoking. # # * Invoke a resource class action. # # * Invoke a resource action. # # B. Initialize a session with RMC. # # C. If a resource handle was specified we need to determine which # # resource class it belongs to. So we can get the data types. # # D. If a selection string and resource class were specified we need # # to get the resource handles associated with the resources that # # match the selection string for the specified class. # # E. Query the definition of the action input. # # F. Query the definition of the action response (output). # # G. Parse the element = value pairs from the command line or # # from the input file. # # H. Invoke the action on each of the resource handles. # # E. Display the Action response. # # F. Cleanup. # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # Included Libraries and Extensions # #--------------------------------------------------------------------# use lib "/opt/rsct/pm"; use locale; use Getopt::Long; use autouse CT_cli_utils => qw( printIMsg printEMsg ); use autouse CT_cli_input_utils => qw( process_input_file process_cmdline_input string_to_rsrc_handle escape_chars check_input_file ); use MC_cli_rc qw(:return_codes); use autouse MC_cli_utils => qw( error_exit build_HoAttr printCEMsg get_class_from_rsrc_hndl_api convert_input_value_api process_api_error process_exit_code remove_api_error read_from_Stdin ); use autouse MC_cli_display_utils => qw( display_resource_data_api3 ); #--------------------------------------------------------------------# # Global Variables # #--------------------------------------------------------------------# Getopt::Long::Configure ("bundling", "no_auto_abbrev", "no_ignore_case", "require_order", "prefix_pattern=(--|-)"); $TRUE = 1; $FALSE = 0; $Verbose = $FALSE; # default - verbose turned off # By default output, attribute name value pairs should be entered # via the command line. Attr=value e.g. Name=c175n06 NodeNumber=1 $Opt_RSRC_Class = $FALSE; # default - see -c (class) $Opt_RSRC_Class_DM = $FALSE; # default - see -C (class) $Opt_Class = $FALSE; # either -C or -c $Opt_File_Input = $FALSE; # default - see -f (file form) $Opt_RSRC_Handle = $FALSE; # default - see -r (rsrc hndl) $Opt_Select_Str = $FALSE; # default - see -s (selectstr) $Opt_Long_Format = $TRUE; # default - see -l (long form) $Opt_Table_Format = $FALSE; # default - see -t (tabular) $Opt_Delm_Format = $FALSE; # default - see -d (delimiter) $Opt_Delm_Str = ":"; # default - see -D (colon :) $Opt_No_HDR = $FALSE; # default - see -x $Opt_Node_File= $FALSE; # default - see -N $Opt_Stdin= $FALSE; # default - see -N with Stdin $PROGNAME = "runact"; # Program Name for messages $MSGCAT = "mccli.cat"; # msg catalogue for this cmd $CTDIR = "/opt/rsct"; # RSCT root directory $CTBINDIR = "$CTDIR/bin"; # Cluster Bin directory path $LSMSG = "$CTBINDIR/ctdspmsg"; # list / display message rtn. $ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps"; # msg maps used by $LSMSG #--------------------------------------------------------------------# # Variables # #--------------------------------------------------------------------# my %HoSDInDef = (); # Action input SD Definition my %HoSDRspDef = (); # Action response SD Def my %HoClassNames = (); my @LoSDIn = (); # Action input SD my @resource_handles = (); my $rsp_elements; # Reference to array of # response element names. my $in_elements; # Reference to array of # In_Element=value pairs my $rc = 0, $badrc = 0; my $rsrc_class_id = 0; my $rHoSD; my $node_names = ""; # -n node names my $peer_domain_names = ""; # -C peer domain names my @node_name_list = (); # node names in an array my $name_count; # number of nodes in list # (only allow 1 today) my $node_file_name; # to hold node filename my @lsr_out = (); # lsrsrcdef-api output my @run_out = (); # runact-api output my $cmdstr = ""; # runact-api parameters my $cmdstr_tmp = ""; # runact-api parameters $DELIMITER = "tvrtvrtvr"; # delimiter for runact-api #--------------------------------------------------------------------# # Main Code # #--------------------------------------------------------------------# # set the quote string environment variable, if necessary if (!defined $ENV{CT_CLI_QUOTE_STRING}){ $ENV{CT_CLI_QUOTE_STRING} = 1; } # parse the command line, exit if there are errors ($rc, $resource, $r_rsrc_handle, $action, $filename, $select_str, $node_names, $peer_domain_names, $node_file_name, $in_elements, $rsp_elements) = &parse_cmd_line; ($rc == 0) || error_exit($rc); # if - N was specified, make sure CT_MANAGEMENT_SCOPE # is set. If it isn't, set it to 4, DM/SR/Local if ($Opt_Node_File && !defined $ENV{CT_MANAGEMENT_SCOPE}) { $ENV{CT_MANAGEMENT_SCOPE} = 4; } # If the -r flag was specified then the user is specifying the # actual resource handle on the command line and wants the # resource associated with this resource handle removed. # Determine which resource class this resource handle is associated. if ($Opt_RSRC_Handle) { $r_rsrc_handle = $resource; ($rc, $resource) = get_class_from_rsrc_hndl_api($r_rsrc_handle); ($rc == 0) || error_exit($rc); push @resource_handles, $r_rsrc_handle; } # set $Opt_Class if either -c or -C used if ($Opt_RSRC_Class || $Opt_RSRC_Class_DM) { $Opt_Class = $TRUE; } # Call lsrsrcdef-api to get the input and response elements # for the action if ($Trace) { print STDERR "$PROGNAME: calling lsrsrcdef-api\n";} # set up flags for resource action my $flg1 = " -tx"; my $flg2 = " -ty"; my $flg3 = " -a"; # change the flags if it's a class action if ($Opt_Class) { $flg1 = " -tX"; $flg2 = " -tY"; $flg3 = " -A"; } @lsr_out = `$CTBINDIR/lsrsrcdef-api $flg3 ${resource}::${action} $flg1 ${resource}::${action} $flg2 ${resource}::${action} 2>&1`; # capture the return code from lsrsrcdef-api $rc = $?; $rc = process_exit_code($rc); if ($Trace) { print STDERR "lsrsrcdef-api results:\n"; print STDERR "@lsr_out"; print STDERR "$PROGNAME: lsrsrcdef-api returned $rc\n";} # show any errors if there was a bad rc if ($rc != 0) { process_api_error("::",$rc,@lsr_out); } # remove any error messages from the output to display @lsr_out = remove_api_error("::",@lsr_out); # exit user error if nothing came back from lsrsrcdef-api # must be action not found if ($#lsr_out < 0) { printCEMsg("EMsgMCcliUndefinedActionName", $resource); exit (MC_CLI_USER_ERROR); } # remove the action def from @lsr_out[0] shift @lsr_out; # form the input and response SD definitionas from the # lsrsrcdef-api output format_sd_element_defs ($resource, \@lsr_out, \%HoSDInDef, \%HoSDRspDef); # Get the SD element=value pairs to construct the action input SD # from either the command line (@$in_elements) or input file. ($rc, $rLoRsrcData) = process_input($Opt_File_Input, $filename, $Opt_Class, $in_elements); ($rc == 0) || error_exit($rc); # if there are no arguments for this action, build the # command without them if ($#$rLoRsrcData <0) { $cmdstr = build_action_input_no_sd($resource, $action, $r_rsrc_handle, $select_str, $node_names, $peer_domain_names); } else { # Merge the attr=value pairs you got from the user with the # resources actual attribute definitions to build a Hash of # Persistent Attributes which contains the equivalent data as # the mc_attribute_t structure ({at_name} {at_dtype} {at_value}) # The data you need to actually define the resource - also # check that the user supplied values for all the required # attributes foreach $new_action (@$rLoRsrcData) { ($rc, $cmdstr_temp) = build_action_input_sd($resource, $action, $r_rsrc_handle, $select_str, $node_names, $peer_domain_names, $new_action, \%HoSDInDef); if ($rc != 0) { if (!$badrc) { $badrc = $rc; } next; } # add it to the final command $cmdstr .= " " . $cmdstr_temp; } # end foreach $new_action } # call runact-api if ($Trace) { print STDERR "$PROGNAME: calling runact-api\n"; print STDERR "$PROGNAME: calling runact-api with $cmdstr\n"; } @run_out = `$CTBINDIR/runact-api -D $DELIMITER -I $DELIMITER $cmdstr 2>&1`; # remove temp node file if from STDIN if ($Opt_Stdin) { unlink($node_file_name); } # capture the return code from runact-api $rc = $?; $rc = process_exit_code($rc); if ($Trace) { print STDERR "runact-api results:\n"; print STDERR "@run_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,@run_out); $badrc = $rc; } # remove any error messages from the output to display @run_out = remove_api_error($DELIMITER,@run_out); # Display the action's response $rc = format_and_display_SD(\@run_out, $rsp_elements, \%HoSDRspDef); ($rc == 0) || error_exit($rc); ($badrc == 0) || exit($badrc); exit $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. # # SR_CLI_BAD_FLAG Command line contained a bad flag. # # $resource Resource Class Name. # # $r_rsrc_handle Reference to a resource handle. # # $action Action Name. # # $rsrc_file Name of file that contains rsrc data # # $select_str Selection string. # # $node_names node name for class action # # @in_elements Reference to an array of # # Input element = value pairs. # # @out_elements Reference to an array of the # # Output element names to be displayed. # # # # Global Variables Modified: # # $Opt_RSRC_Class output True (-c), invoke action on resource # # class. # # $Opt_RSRC_Class_DM output True (-C), invoke action on resource # # class on peer domains in DM scope. # # $Opt_Select_Str output True (-s select_string), invoke # # action on resources that match # # specified selection string. # # $Opt_RSRC_Handle output True (-r), invoke action on this # # resource handle specified as operand.# # $Opt_File_Input output True (-f) read rsrc data from file. # # $Opt_Long_Format output True (-l) print one entry per line # # $Opt_Table_Format output True (-t) print in table format. # # $Opt_Delm_Format output True (-d|-D) print delimitter # # separated output. # # $Opt_Delm_Str output the string to use as the delimitter, # # default is colon (:). # # $Opt_No_HDR output True (-x) print without header # # $Verbose output True (-V) turn Verbose mode on. # # $Trace output True (-T) turn Trace mode on. # #--------------------------------------------------------------------# sub parse_cmd_line { my(@original_argv) = @ARGV; my $resource = ""; my $action = ""; my $rsrc_file = ""; my $select_str = ""; my @in_elements = (); my @out_elements = (); my $node_names = ""; my $peer_domain_names = ""; my $node_file_name= ""; my $rc; my %opts = (); # Process the command line... if (!GetOptions(\%opts, 'h|help|version' , 'c' , 'd' , 'l' , 'r' , 't' , 'T' , 'V' , 'x' , 'C=s' , 'D=s' , 'f=s' , 'n=s' , 'N=s' , 's=s' )) { &print_usage; # display proper usage return MC_CLI_BAD_FLAG; # return bad rc - bad flag } # Always accept the -h help flag regardless of other flags or operands if (defined $opts{h}) { # -h, help request &print_usage; # print usage statement exit(0); # all done with good return! } # An operand is required. # When -s flag specified require operand to be a resource class name # When -r flag specified require operand to be a resource handle if ($#ARGV >= 0) { # Get the arguments... # Operands: [resource | resource_handle] $resource = shift @ARGV; # user specified resources if ($#ARGV >= 0) { $action = shift @ARGV; # user specified action } else { printCEMsg("EMsgMCcliMissingAction"); &print_usage; return MC_CLI_BAD_OPERAND; # return bad rc - bad operand } } else { (defined $opts{s}) && printCEMsg("EMsgMCcliMissingRsrcClass"); (defined $opts{r}) && printCEMsg("EMsgMCcliMissingRsrcHandle"); &print_usage; return MC_CLI_BAD_OPERAND; # return bad rc - bad operand } # need to handle sd input and # Grab all of the In_Element=value pairs that must come before the # Out_Element operands. The regular expression sees if the next # argument / operand is of the form keyword=value. if ($#ARGV >= 0) { my $num_elements = $#ARGV + 1; for (my $i= 0; $i < $num_elements; $i++) { if ($ARGV[0] =~ /(\w+)\s*=\s*(.*?)\s*/) { # arg keyword=value push @in_elements, shift @ARGV; } else { last; } } } # The remaining arguments / operands are the Out_Elements # The Action output response element names that should be displayed if ($#ARGV >= 0) { @out_elements = @ARGV; } # See which options/flags were used... if (defined $opts{c}) { # -c, invoke act on rsrc class $Opt_RSRC_Class = $TRUE; if (defined $opts{s}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-c", "-s"); &print_usage; return MC_CLI_BAD_FLAG; } # check for -n node_names option if (defined $opts{n}) { $node_names = $opts{n}; } } if (defined $opts{C}) { # -C, invoke act on rsrc class $Opt_RSRC_Class_DM = $TRUE; $peer_domain_names = $opts{C}; if (defined $opts{s}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-s"); &print_usage; return MC_CLI_BAD_FLAG; } if (defined $opts{c}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-c"); &print_usage; return MC_CLI_BAD_FLAG; } if (defined $opts{n}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-n"); &print_usage; return MC_CLI_BAD_FLAG; } } if (defined $opts{f}) { # -f, filename for rsrc data $Opt_File_Input = $TRUE; $rsrc_file = $opts{f}; # input rsrc file name if (scalar @in_elements > 0) { # Can't use -f with In_element on cmd line printCEMsg("EMsgMCcliImproperUsageCombination", "-f", @in_elements); &print_usage; return MC_CLI_BAD_OPERAND; } } if (defined $opts{r}) { # -r, rm using rsrc handles $Opt_RSRC_Handle = $TRUE; ($rc, $r_rsrc_handle) = string_to_rsrc_handle($resource); if ($rc != 0) { printCEMsg("EMsgMCcliBadRsrcHandle", $resource); &print_usage; return MC_CLI_BAD_OPERAND; } if (defined $opts{c}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-c", "-r"); &print_usage; return MC_CLI_BAD_FLAG; } if (defined $opts{n}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-n", "-r"); &print_usage; return MC_CLI_BAD_FLAG; } if (defined $opts{s}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-s", "-r"); &print_usage; return MC_CLI_BAD_FLAG; } if (defined $opts{C}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-r"); &print_usage; return MC_CLI_BAD_FLAG; } } if (defined $opts{s}) { # -s "selection_string" $select_str = $opts{s}; # don't allow empty selection string if ($select_str =~ /^$/) { printCEMsg("EMsgMCcliSelectStrError"); &print_usage; return MC_CLI_BAD_OPERAND; } $Opt_Select_Str = $TRUE; } elsif (!defined $opts{c} && !defined $opts{r} && !defined $opts{C}) { printCEMsg("EMsgMCcliMissingSelectionStr"); &print_usage; return MC_CLI_BAD_FLAG; } if (defined $opts{N}) { if (!defined $opts{s}) { # A selection string is required when using -N printCEMsg("EMsgMCcliMissingSelectionStr"); &print_usage; return MC_CLI_BAD_FLAG; } elsif (defined $opts{c}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-c"); &print_usage; return MC_CLI_BAD_FLAG; } elsif (defined $opts{C}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-C"); &print_usage; return MC_CLI_BAD_FLAG; } elsif (defined $opts{r}) { printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-r"); &print_usage; return MC_CLI_BAD_FLAG; } elsif ($opts{N} eq "-") { $Opt_Stdin= $TRUE; } else { $node_file_name= $opts{N}; $node_file_name = escape_chars($node_file_name); $rc= check_input_file($node_file_name); if ($rc) { return MC_CLI_BAD_OPERAND; } } $Opt_Node_File= $TRUE; } # The -l overrides the -t which overrides the -d which overrides -D # Long is the default display format if (defined $opts{l}) { $Opt_Long_Format = $TRUE; } elsif (defined $opts{t}) { $Opt_Table_Format = $TRUE; # -t tabular format $Opt_Long_Format = $FALSE; } elsif (defined $opts{d}) { # -d delimitter format $Opt_Delm_Format = $TRUE; $Opt_Long_Format = $FALSE; } elsif (defined $opts{D}) { # -D format $Opt_Delm_Format = $TRUE; $Opt_Long_Format = $FALSE; $Opt_Delm_Str = $opts{D}; } if (defined $opts{x}) { # -x do not print header $Opt_No_HDR = $TRUE; } if (defined $opts{T}) { # -T, turn tracing on $Trace = $TRUE; } if (defined $opts{V}) { # -V, turn verbose mode on $Verbose = $TRUE; } # success return(0, $resource, $r_rsrc_handle, $action, $rsrc_file, $select_str, $node_names, $peer_domain_names, $node_file_name, \@in_elements, \@out_elements); } # end parse_cmd_line #--------------------------------------------------------------------# # print_usage : print the usage statement (syntax) to stdout. # # See this command's prologue syntax section for current usage. # #--------------------------------------------------------------------# sub print_usage { printIMsg("IMsgrunactUsage4"); } # end print_usage #--------------------------------------------------------------------# # format_sd_element_defs - formats the structured data elements into # # a complex hash of SD element definitions (%rHoSDEleDefs). # # The level 1 hash # # key = element_name data = hash # # or # # key = element_index data = hash # # Typically when processing the SD input def we want the key # # to be the element_name. But when processing the SD response def # # where we want to display the response SD, having the key as # # the SD element index makes more sense. # # The level 2 hash # # key = (sd_name, sd_dtype, sd_index, sd_value) # # the values from mc_qdef_sd_bp of those fields # # Example: # # x $rHoSDEleDefs # # 0 'Int32' # # 1 HASH(0x2045ddd0) # # 'sd_dtype' => 2 # # 'sd_index' => 0 # # 'sd_name' => 'Int32' # # 'sd_value' => undefined # # or # # 0 0 # # 1 HASH(0x2045ddd0) # # 'sd_dtype' => 2 # # 'sd_index' => 0 # # 'sd_name' => 'Int32' # # 'sd_value' => undefined # # # # Parameters: # # $resource input Resource Name # # $response input Reference to array returned by # # lsrsrcdef-api. # # %$rHoSDEleDefs in/out Reference to the hash of SD element # # definitions. # # $hash_by_name input TRUE - hash by element_name. # # FALSE - hash by element_index. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub format_sd_element_defs { #my($resource, $response, $rHoSDEleDefs, $hash_by_name) = @_; my($resource, $response, $rHoSDEleDefsIn, $rHoSDEleDefsResp) = @_; my %elements = (); my @resp_info = (); my ($element_name, $element_index, $element_cnt); # get count of array elements my $response_cnt = $#$response; # keep track of if we're processing input or response my $Input = $TRUE; # check if there are no input elements if ( ($response_cnt >= 0) && ($$response[0] =~ /^.*::\"OUT\"::/) ) { $Input = $FALSE; } # form the hash for (my $e = 0; $e <= $response_cnt; $e++) { %elements = (); chomp($$response[$e]); @resp_info = split (/::/, $$response[$e]); $element_name = $resp_info[2]; $element_name =~ s/\"//g; $element_index = $resp_info[6]; $elements{sd_name} = $element_name; $elements{sd_index} = $element_index; $elements{sd_dtype} = $resp_info[3]; # assign to proper structure if ($Input) { $$rHoSDEleDefsIn{$element_name} = { %elements }; } else { $$rHoSDEleDefsResp{$element_name} = { %elements }; } # see if input has ended and responses are next if ( ($e < $response_cnt) && ($$response[$e+1] =~ /^.*::\"OUT\"::/) ) { $Input = $FALSE; } } # end for each response return; } # end of format_sd_element_defs #--------------------------------------------------------------------# # process_input - process the attr=value pairs that are used to # # define this resource and were input by the user on the command # # line or via an input file. # # # # Parameters: # # $Opt_File_Input input True - input should come from file. # # False - input should come from command # # line. # # $filename input Name of file if $Opt_File_Input = TRUE # # $Opt_Class input True if invoking action on a resource # # class instead of a resource. # # @$r_cmdline input Reference to attr=value pairs via # # command line and ARGV. # # # # Return: # # $rc return code. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub process_input { my ($Opt_File_Input, $filename, $Opt_Class, $r_cmdline) = @_; my $rc = 0; my $rLoRsrcData; if ($Opt_File_Input) { my $file_stanza; if ($Opt_Class) { $file_stanza = "ResourceClassAction"; } else { $file_stanza = "ResourceAction"; } ($rc, $rLoRsrcData) = process_input_file($filename, $file_stanza); if ($rc != 0) { # Print Error processing input file msg # process_input_file will write a more detailed error message printEMsg("EMsgrunactInputFileError", $filename); exit(MC_CLI_USER_ERROR); } } else { # set empyt list if no args if ($#$r_cmdline < 0) { $rLoRsrcData = $r_cmdline; } # process the args else { ($rc, $rLoRsrcData) = process_cmdline_input($r_cmdline); if ($rc != 0) { # Print Command Line Error Attr=value error msg printEMsg("EMsgrunactCmdLineError", $r_cmdline); exit(MC_CLI_BAD_OPERAND); } } } if ($Verbose) { my ($attribute, $value, $entry, $row_header); foreach $entry (@$rLoRsrcData) { $row_header = $entry->[0]; foreach $element (@{$entry->[1]}) { $attribute = $element->[0]; $value = $element->[1]; print "$attribute = \"$value\"\n"; } } } return ($rc, $rLoRsrcData); } # end process_input #--------------------------------------------------------------------# # build_action_input_sd - function to build up the parameters for # # the runact-api command. # # # # Parameters: # # $resource input Resource name. # # $action input Action name. # # $handle input Resource handle. # # $selstr input Select string. # # $node_name input Node name. # # $peer_domain_names input Peer domain names. # # $rActionData input Reference to array of attr,value pairs.# # $rHoSDInDef input Reference to hash of the action input # # SD element definitions for this action.# # # # Return: # # $rc return code. # # $runcmd String containing runact-api parms. # # # # Global References: # # Opt_RSRC_Class input Class action (-c). # # Opt_RSRC_Class_DM input Class action (-C). # # Opt_RSRC_Handle input Resource handle specified (-r). # # Opt_Select_Str input Select string specified (-s). # # DELIMITER input Input delimiter. # #--------------------------------------------------------------------# sub build_action_input_sd { my ($resource, $action, $handle, $selstr, $node_name, $peer_domain_names, $rActionData, $rHoSDInDef) = @_; my ($new_element, $data_type); my $element_list = ""; my ($element_name, $element_value); my $badrc = 0; my $runcmd = ""; my $delim = ""; foreach $new_element (@{$rActionData->[1]}) { $element_name = $new_element->[0]; # first check to make sure this is a valid sd element name if (!defined($$rHoSDInDef{$element_name})) { printEMsg("EMsgrunactInvalidSDElement", $element_name, $resource, $action, '"' . $rActionData->[0] . '"'); $badrc = MC_CLI_USER_ERROR; next; # continue validating rest of input } # Get the elements value $data_type = $rHoSDInDef->{$element_name}{sd_dtype}; # An SD cannot contain an SD if (($data_type =~ /^CT_SD_PTR$/) || ($data_type =~ /^CT_SD_PTR_ARRAY$/)) { printEMsg("EMsgrunactInvalidDataType", $action, $element_name, $data_type); $rc = MC_CLI_USER_ERROR; } $element_value = $new_element->[1]; # get rid of quotes in arrays, but not in string arrays if ( ($data_type =~ /ARRAY$/) && ($data_type !~ /^CT_CHAR_PTR_ARRAY$/) ) { $element_value =~ s/\"//g; } $element_list .= $delim . $element_name . $DELIMITER . $element_value; $delim = $DELIMITER; } # put the command together # for class, it's -c class::node:: if ($Opt_RSRC_Class) { $runcmd = "-c \"${resource}${DELIMITER}${node_name}"; } # for class, it's -C class::peer_domain_names:: if ($Opt_RSRC_Class_DM) { $runcmd = "-C \"${resource}${DELIMITER}${peer_domain_names}"; # set DM scope for -C $ENV{CT_MANAGEMENT_SCOPE} = 3; } # for resource handle, it's -r handle:: elsif ($Opt_RSRC_Handle) { $runcmd = "-r \"$handle"; } # for select string, it's -s class::select_str elsif ($Opt_Select_Str) { $selstr = escape_chars($selstr); if ($Opt_Node_File) { # create temp file based on Stdin input if ($Opt_Stdin) { $node_file_name= read_from_Stdin(); } $runcmd = "-w \"${resource}${DELIMITER}${selstr}${DELIMITER}${node_file_name}"; } else { $runcmd = "-s \"${resource}${DELIMITER}${selstr}"; } } $element_list = escape_chars($element_list); # add the action and arg/value pairs $runcmd .= $DELIMITER . $action . $DELIMITER . $element_list . "\""; return($badrc, $runcmd); } # end build_action_input_sd #--------------------------------------------------------------------# # build_action_input_no_sd - function to build up the parameters for # # the runact-api command when no arguments are used. # # # # Parameters: # # $resource input Resource name. # # $action input Action name. # # $handle input Resource handle. # # $selstr input Select string. # # $node_name input Node name. # # $peer_domain_names input Peer domain names. # # # # Return: # # $runcmd String containing runact-api parms. # # # # Global References: # # Opt_RSRC_Class input Class action (-c). # # Opt_RSRC_Class_DM input Class action (-C). # # Opt_RSRC_Handle input Resource handle specified (-r). # # Opt_Select_Str input Select string specified (-s). # # DELIMITER input Input delimiter. # #--------------------------------------------------------------------# sub build_action_input_no_sd { my ($resource, $action, $handle, $selstr, $node_name, $peer_domain_names) = @_; my $runcmd = ""; my $delim = ""; # put the command together # for class, it's -c class::node:: if ($Opt_RSRC_Class) { $runcmd = "-c \"${resource}${DELIMITER}${node_name}"; } # for class, it's -C class::peer_domain_names:: if ($Opt_RSRC_Class_DM) { $runcmd = "-C \"${resource}${DELIMITER}${peer_domain_names}"; # set DM scope for -C $ENV{CT_MANAGEMENT_SCOPE} = 3; } # for resource handle, it's -r handle:: elsif ($Opt_RSRC_Handle) { $runcmd = "-r \"$handle"; } # for select string, it's -s class::select_str elsif ($Opt_Select_Str) { # escape inner quotes $selstr = escape_chars($selstr); if ($Opt_Node_File) { # create temp file based on Stdin input if ($Opt_Stdin) { $node_file_name= read_from_Stdin(); } $runcmd = "-w \"${resource}${DELIMITER}${selstr}${DELIMITER}${node_file_name}"; } else { $runcmd = "-s \"${resource}${DELIMITER}${selstr}"; } } # add the action and arg/value pairs $runcmd .= $DELIMITER . $action . "\""; return($runcmd); } # end build_action_input_sd #--------------------------------------------------------------------# # format_and_display_SD - formats and displays the action response # # SD elements. # # # # Parameters: # # $response input Reference to array of runact-api # # output. # # $rlo_elements input Reference to list of SD element names. # # If empty print all SD elements else # # print only the ones specified. # # %$rHoSDRspDef input Reference to the hash of SD response # # definition (from get_sd_element_defs) # # x %$rHoSDRspDef to see format of hash. # # # # Global References: # # $Opt_Long_Format input TRUE if should display one per line. # # $Opt_Table_Format input TRUE if should display in table form. # # $Opt_Delm_Format input TRUE if should display with delimiter. # # $Opt_Delm_Str input Actual delimiter to display with. # # $Opt_No_HDR input TRUE if should not display header. # # $Opt_Class input TRUE if -c or -C used. # #--------------------------------------------------------------------# sub format_and_display_SD { my ($response, $rlo_elements, $rHoSDRspDef) = @_; my @LoElements = (); my %HoElements = (); my %elements = (); my ($element_name, $element_count); my $TOO_MANY = 100; my $title_col; my @title_row; my $print_format = "long"; my $delim = ""; my $idcount = 0; my $start_num = 0; my $rc = 0; # Determine if displaying in long, delimiter or tabular/column format. if ($Opt_Long_Format) { $print_format = "long"; } elsif ($Opt_Table_Format) { $print_format = "column"; } elsif ($Opt_Delm_Format) { $print_format = "delim"; $delim = $Opt_Delm_Str; } $title_row = "sd_element"; my @r_info = (); my $node_name = ""; my $response_count = $#$response; my $s = 0; # number of SDs to be displayed # if there's alot of data, make this 2 pass by forming the list of element # names first, and then filling in the hash to display multiple times. if ($response_count >= $TOO_MANY) { for (my $r = 0; $r <= $response_count; $r++) { # parse each response chomp($$response[$r]); @r_info = split (/$DELIMITER/, $$response[$r]); # if there is an odd number of array elements, the # first is the node name of where it came from my $rem = $#r_info % 2; if (!$rem) { $node_name = shift @r_info; } # format the responses for (my $k = 0; $k <= $#r_info; $k=$k+2) { $element_name = $r_info[$k]; if ( (!exists ${$rHoSDRspDef}{$element_name}{sd_dtype}) && ( $element_name =~ /^\(CT\_/) ) { $idcount = $k/2; $element_name = "ACT_RSP_ELE_$idcount"; } if (!(exists $HoElements{$element_name})) { # add the new attribute to the list of attributes push @LoElements, $element_name; # Add an empty array for this new attr name my @fields = (); $HoElements{$element_name} = [ @fields ]; } } } # end for each response } # Display the header to the output here since it needs # to use a catalogued message. $title_col = ""; if (!$Opt_No_HDR) { ($Opt_Class) ? printIMsg("IMsgrunactRsrcClassRspHdr", $action) : printIMsg("IMsgrunactRsrcActRspHdr", $action); } # break up processing the output, if necessary for (my $ii = 0; $ii < int( ($response_count / $TOO_MANY) +1); $ii++) { $s=0; for (my $r = $ii * $TOO_MANY; ($r < ($ii+1)*$TOO_MANY) && ($r <= $response_count); $r++) { # parse each response chomp($$response[$r]); @r_info = split (/$DELIMITER/, $$response[$r]); # if there is an odd number of array elements, the # first is the node name of where it came from my $rem = $#r_info % 2; if (!$rem) { $node_name = shift @r_info; } # my @loSDs = $response->data($r); # format the responses for (my $k = 0; $k <= $#r_info; $k=$k+2) { %elements = (); $element_name = $r_info[$k]; $elements{at_name} = $element_name; $elements{at_dtype} = ${$rHoSDRspDef}{$element_name}{sd_dtype}; if ( (!exists ${$rHoSDRspDef}{$element_name}{sd_dtype}) && ( $element_name =~ /^\(CT\_/) ) { $elements{at_dtype} = $element_name; $elements{at_dtype} =~ s/^\(//; $elements{at_dtype} =~ s/\)$//; $idcount = $k/2; $element_name = "ACT_RSP_ELE_$idcount"; $elements{at_name} = $element_name; } $elements{at_value} = $r_info[$k+1]; # quote any resource handles and binary values if ( ($elements{at_dtype} =~ /^CT_RSRC_HANDLE_PTR$/) || ($elements{at_dtype} =~ /^CT_BINARY_PTR$/) ) { $elements{at_value} = "\"" . $elements{at_value} . "\""; } if ( ($elements{at_dtype} =~ /^CT_RSRC_HANDLE_PTR_ARRAY$/) || ($elements{at_dtype} =~ /^CT_BINARY_PTR_ARRAY$/) ) { $elements{at_value} =~ s/\{/\{\"/; $elements{at_value} =~ s/\}/\"\}/; $elements{at_value} =~ s/,/\",\"/g; } build_HoAttr($element_name, \@LoElements, \%HoElements, \%elements, $s); } $s++; # number of SDs to be displayed } # end for each response # Display the SD elements in the order that they were requested # on the command line. If no response element names were specified # on the command line display them in the order that RMC returned # them. if (scalar(@$rlo_elements) == 0) { $rlo_elements = \@LoElements; } else { # ensure all response elements from cmd line are valid foreach $element (@$rlo_elements) { if ((!exists ${$rHoSDRspDef}{$element}) && ($element !~/^ACT_RSP_ELE/)) { printEMsg("EMsgrunactBadRspElt", $element, $action); $rc = MC_CLI_USER_ERROR; } } ($rc == 0) || return $rc; } # Only display table header first time display everything from # one response $start_num = ($ii * $TOO_MANY)+ 1; $rc = display_resource_data_api3($print_format, $Opt_No_HDR, $rlo_elements, $title_row, \%HoElements, $delim, $title_col, $start_num); # reset the hash in case we have to do it again for more data %HoElements = (); foreach $element (@LoElements) { # Add an empty array for this attr name my @fields = (); $HoElements{$element} = [ @fields ]; } } return $rc; } # end format_and_display_SD #--------------------------------------------------------------------# # error_check - checks the return code from the RMC function and # # the error response return code. If an error is detected # # appropriate error messages will be displayed. # # # # Parameters: # # $rmc_function in Name of the rmc function that was # # called and whose error code we are # # checking. # # $rmc_class in The resource class name. # # $action in The action name. # # $response in RMC response. # # $rmc_rc in The rmc function return code. # # $error in The error response. # # # # Return: # # $rc return code. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub error_check { my ($rmc_function, $rmc_class, $action, $response, $rmc_rc, $error) = @_; my $rc = 0; my $err_rc = $error->errnum(); if ($rmc_rc != 0) { printEMsg("EMsgrunactRunActError", $action); my $rmc_rc_hex = sprintf "0x%8.8lx", $rmc_rc; printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function, $rmc_rc, $rmc_rc_hex); $rc = MC_CLI_RMC_ERROR; return $rc; } # Check the errnum in each of the RMC responses for (my $r = 0; $r < $response->array_count; $r++) { # get the error that goes with the specific response if ($r > 0) { $response->error($error, $r); $err_rc = $error->errnum(); } if ($err_rc != 0) { if ($err_rc == RMC_ECLASSNOTDEFINED) { printCEMsg("EMsgMCcliClassNotDef", $rmc_class); $rc = MC_CLI_USER_ERROR; } elsif ($err_rc == RMC_EBADACTIONNAM) { print STDERR $error->error_msg; $rc = MC_CLI_USER_ERROR; } elsif ($err_rc == RMC_EACCESS) { print STDERR $error->error_msg; $rc = MC_CLI_USER_ERROR; } elsif ($err_rc >= 0x60000 && $err_rc <= 0x6ffff) { # Selection string errors are in this range printCEMsg("EMsgMCcliSelectStrError"); print STDERR $error->error_msg; $rc = MC_CLI_USER_ERROR; } else { printEMsg("EMsgrunactRunActError", $action); my $err_rc_hex = sprintf "0x%8.8lx", $err_rc; printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function, $err_rc, $err_rc_hex); print STDERR $error->error_msg; $rc = MC_CLI_RMC_ERROR; } } # end if } # end for return $rc; } # end error_check