# IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2001 # 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 package MC_cli_sd_utils; # sccsid = "@(#)58 1.6 src/rsct/rmc/cli/pm/MC_cli_sd_utils.pm.perl, rmccli, rsct_rady, rady2035a 11/12/15 16:30:02" ###################################################################### # # # Package: MC_cli_sd_utils.pm # # # # Description: # # This package contains utility/common subroutines for the PERL # # Cluster Resource Monitoring and Control (RMC) CLI commands # # that are specific to dealing with the structured data (sd) type. # # An SD is one of the basic cluster data types defined in ct.h. # # # # Subroutines Available: # # get_sd_element_defs - function to get the structured data # # definition for the specified class, name (attribute or # # action name) and usage. Specifically the elements definition # # that make up the SD. Uses the mc_qdef_sd_bp and builds a hash # # indexable by either element name or index depending on input # # argument to this function. Which SDs are returned is also # # controled by the usage paramater. # # # # get_sd_element_names - returns a list of SD element names in # # element index order. # # # # qdef_sd - convenience function to call the Perl to C extension # # for mc_qdef_sd_bp and return the response. # # # # format_sd_element_defs - formats the data returned in # # the response of the mc_qdef_sd_bp into a hash of structured # # data elements definitions indexable by the element name or # # index depending on input parameter. # # If the number of names the qdef_sd was passed is greater than # # 1 you should use format_sd_attr_defs. # # # # format_sd_attr_defs - formats the data returned in # # the response of the mc_qdef_sd_bp into a hash of attribute/ # # action names, that point to a hash of structured # # data elements definitions indexable by the element name. # # This differs from format_sd_element_defs in that the highest # # level hash is a hash of attribute names that contains the # # hash of SD elements for that attribute. # # # # build_cmd_arg_sd - builds the command argument SD in value_t # # format. The format the Perl to C extensions expect based on # # what the RMC C API expects. Verifies that each SD element in # # the HoSDEleDefs has a value then builds in element index order # # the value_t representation of the SD. # # # # Examples: # # ($rc $session) = init_session(); # # $rc = term_session($session); # # # #--------------------------------------------------------------------# # Inputs: # # /opt/rsct/msgmaps/mccli.mccli.map - message mapping # # # # Outputs: # # stdout - common informational messages that get displayed. # # stderr - common error messages that get displayed. # # # # External References: # # Commands: ctdspmsg # # # # Tab Settings: # # 4 and tabs should be expanded to spaces before saving this file. # # in vi: (:set ts=4 and :%!expand -4) # # # # Change Activity: # # 010720 SAB 75111: Initial design & write. # # 020116 JAC 78199: Change build_cmd_arg_sd to handle no args. # ###################################################################### use Exporter (); @ISA = qw(Exporter); @EXPORT_OK = qw( get_sd_element_defs get_sd_element_names qdef_sd format_sd_element_defs format_sd_attr_defs build_cmd_arg_sd ); use lib "/opt/rsct/pm"; use locale; ##use CT::CT qw( ## :ct_data_type_t ##); use autouse CT_cli_input_utils => qw( convert_input_value ); ##use CT::MC; # import defaults ##use CT::MC qw( ## :mc_qdef_opts_t ## :mc_sd_usage_t ## qdef_sd_bp ## free_response ##); ##use CT::MCerr; # RMC return/error codes ##use CT::RM; # RM return/error codes use MC_cli_utils qw( printCIMsg printCEMsg ); use MC_cli_rc qw(:return_codes); #--------------------------------------------------------------------# # Global Variables # #--------------------------------------------------------------------# $MSGCAT = "mccli.cat"; # msg catalogue for this cmd $MSGSET = "mccli"; # common message set $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 #--------------------------------------------------------------------# # Exported Subroutines (with @EXPORT_OK, -> on demand). # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # Common message handling (error, informational) routines: # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # get_sd_element_defs - function to get this resource's structured # # data element definitions using mc_qdef_sd_bp and build a hash # # indexable by the element name with the element name, data type, # # index, and value stored as data. # # # # Parameters: # # $session input RMC session handle. # # $resource input Resource class name. # # $name input An action name or attribute name or # # empty string. Doing a qdef on an # # action requires an action name or # # more than one may be returned. Doing # # a qdef_sd on a command argument usage # # does not require a name. # # $sd_usage input mc_sd_usage_t as defined in CT::MC.pm # # MC_SD_USAGE_PATTR_RSRC_CLASS, ... # # MC_SD_USAGE_RESET_ARG # # $hash_by_name input 1 - True - Level 1 of hash should be # # the SD element name. # # 0 - False - Level 1 of hash should be # # the SD element index. # # %$rHoSDEleDef in/out Reference to a hash of an SD # # definition. # # key = element_name # # data = hash # # sd_dtype = value # # sd_index = value # # sd_element_name = value # # sd_value = (undefined a place holder # # value entered via command line) # # # # Return: # # $rc return code. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub get_sd_element_defs { my ($session, $resource, $name , $sd_usage, $hash_by_name, $rHoSDEleDefs) = @_; my $rc = 0; my @names = (); if (defined $name && $name ne "") { push @names, $name; } # Need the right response data structure my $response = CT::MC::qdef_sd_rsp_t->new; # Let the subroutine make the call to the extension, and # handle all the assorted potential errors. # Get the command arguments SD definition for the online command $rc = qdef_sd($session, $resource, \@names, $sd_usage, $response); ($rc == 0) || return($rc); format_sd_element_defs($resource, $response, $rHoSDEleDefs, $hash_by_name); if ($response->array_count > 0) { $rc = CT::MC::free_response($response); ($rc == 0) || return $rc; } return $rc; } # end get_sd_element_defs #--------------------------------------------------------------------# # get_sd_element_names - Return a list of the SD element names # # in element index order. # # # # Parameters: # # %$rHoSDDef input Reference to a hash of 1 SD elements # # definition. # # key = action_id # # data = hash # # key = element_name # # data = hash # # sd_dtype = value # # sd_index = value # # sd_element_name = value # # # # Return: # # @sd_element_names Returns an array of the SD element # # names in element index order. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub get_sd_element_names { my ($rHoSDDef) = @_; my @sd_element_names; my %index_to_names = (); my @element_indexes = (); my ($element_name, $element_index); # Prepare to create the list of element names in element index order # When you build up an SD for RMC the elements must be in # the correct order, no guarantee that their won't be spaces # also don't know if mc_qdef_sd_mc provides elements in order. my @element_names = keys %$rHoSDDef; # If only 1 element in SD - no need to sort it. if (scalar @element_names <= 1) { return (@element_names); } foreach $element_name (@element_names) { $element_index = $$rHoSDDef{$element_name}{sd_index}; push @element_indexes, $element_index; $index_to_names{$element_index} = $element_name; } # No guarantee the element indexes are in sorted order so # need to sort them. sub numerically { $a <=> $b; } my @sorted_element_indexes = sort numerically @element_indexes; # Create the list of element names in element index order foreach $element_index (@sorted_element_indexes) { push @sd_element_names, $index_to_names{$element_index}; } return (@sd_element_names); } # end get_sd_element_names #--------------------------------------------------------------------# # qdef_sd - function to call the CT::MC::qdef_sd_bp extension and # # handle possible errors. # # # # Parameters: # # $session input RMC session handle. # # $resource input Resource class name. # # $names input Reference to array of attribute or # # action names or empty array. # # $sd_usage input mc_sd_usage_t as defined in CT::MC.pm # # MC_SD_USAGE_PATTR_RSRC_CLASS, ... # # MC_SD_USAGE_RESET_ARG # # $response in/out qdef_sd response. # # # # Return # # $rc return code. # # # # Global References: # # $main::Trace input TRUE - trace turned on. # #--------------------------------------------------------------------# sub qdef_sd { my ($session, $resource, $names, $sd_usage, $response) = @_; my $rc = 0; my $names_count = scalar(@$names); my $error = CT::MC::errnum_t->new; my $options = MC_QDEF_OPTS_NODSCRP; $main::Trace && print STDERR "Calling CT::MC::qdef_sd_bp\n"; $rc = CT::MC::qdef_sd_bp($session, $response, $error, $options, $resource, $sd_usage, $names, $names_count); $main::Trace && print STDERR "Return CT::MC::qdef_sd_bp\n"; $rc = error_check("mc_qdef_sd_bp", $resource, $response, $rc, $error); return($rc); } # end qdef_sd #--------------------------------------------------------------------# # 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 Response data structure. # # %$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 %elements = (); my ($element_name, $element_index, $element_cnt); my $response_cnt = $response->array_count; # Should only be one response, should only be dealing with # 1 SD at a time here. # TODO: We should display an internal message error if # $response_cnt > 1. If it is then format_sd_attr_defs is # what should probably have been called - since qdef_sd # was probably passed 1 or more names. for (my $r = 0; $r < $response_cnt; $r++) { # The action id is in $response->id($r) if you later # want to save it. For now only dealing with 1 action $element_cnt = $response->element_count($r); for (my $e = 0; $e < $element_cnt; $e++) { %elements = (); $element_name = $response->element_name($r, $e); $element_index = $response->element_index($r, $e); $elements{sd_name} = $element_name; $elements{sd_index} = $element_index; $elements{sd_dtype} = $response->element_data_type($r, $e); # $elements{sd_value} = No value hear yet - this is a place # holder, it will be added in build_cmd_arg_sd if ($hash_by_name) { $$rHoSDEleDefs{$element_name} = { %elements }; } else { $$rHoSDEleDefs{$element_index} = { %elements }; } } # end for each element } # end for each response return; } # end of format_sd_element_defs #--------------------------------------------------------------------# # format_sd_attr_defs - formats the structured data elements into a # # complex hash of SD element definitions (%rHoSDAttrDefs). # # Each SD attribute is an entry in the hash. # # Which points to hash of its SD elements # # Each SD element contains a hash containing values for # # the: sd_dtype, sd_index, sd_name, sd_value. # # # # x $rHoSDAttrDefs # # 0 HASH(0x2004da68) # # 'SD' => HASH(0x206c67b0) # # 'String' => HASH(0x206f1a00) # # 'sd_dtype' => 8 # # 'sd_index' => 0 # # 'sd_name' => 'String' # # 'sd_value' => 'String' # # # # Use the following syntax to access the definitions of a # # particular SD element. # # $$rHoSDAttrDefs{$attr_name}{$sd_element_name} # # The order of the SD element names in @rLoSDAttrDefs should # # correspond to the index of the element in the SD. # # TODO: Check to make sure that's true... # # for each $sd_name @$rLoSDAttrDefs { # # $$rHoSDAttrDefs{$sd_name}{sd_dtype} - SD element data type. # # $$rHoSDAttrDefs{$sd_name}{sd_index} - SD element index. # # $$rHoSDAttrDefs{$sd_name}{sd_value} - SD element value. # # } # # # # Parameters: # # $resource input Resource Name # # $response input Response data structure. # # %$rHoSDAttrDefs in/out Reference to the hash of SD attributes # # (elements) definitions. # # {sd_dtype} and {sd_value}. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub format_sd_attr_defs { my($resource, $response, $rHoSDAttrDefs) = @_; my($attr_name, $attr_id, $r); my %elements = (); $response_cnt = $response->array_count; for ($r = 0; $r < $response_cnt; $r++) { $attr_name = $response->program_name($r); $$rHoSDAttrDefs{$attr_name} = (); $element_cnt = $response->element_count($r); for ($e = 0; $e < $element_cnt; $e++) { %elements = (); $elements{sd_name} = $response->element_name($r, $e); $elements{sd_index} = $response->element_index($r, $e); $elements{sd_dtype} = $response->element_data_type($r, $e); $elements{sd_value} = $response->element_name($r, $e); $rHoSDAttrDefs->{$attr_name}->{$elements{sd_name}} = { %elements }; } # end for each element } # end for each response return; } # end of format_sd_attr_defs #--------------------------------------------------------------------# # build_cmd_arg_sd - builds the command argument SD in value_t # # format. The format the Perl to C extensions expect based on # # what the RMC C API expects. Verifies that each SD element in # # the HoSDEleDefs has a value then builds in element index order # # the value_t representation of the SD. # # SD is represented in Perl as a complex structure. A list of # # hashes. Where each hash represents one SD element, and it # # contains 2 hashes representing the type and value. # # # # Parameters: # # $resource input Resource name. # # $rNameValue input Reference to array of name,value pairs.# # $rHoSDDef input Reference to hash of command SD # # argument element definitions for this # # command. # # # # Return: # # $rc return code. # # @LoSD Structured data complex hash. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub build_cmd_arg_sd { my ($resource, $rNameValue, $rHoSDDef) = @_; my ($new_element, $data_type); my ($element_name, $element_value); my $badrc = 0; my $rc = 0; foreach $new_element (@{$rNameValue->[1]}) { $element_name = $new_element->[0]; # first check to make sure this is a valid sd element name if (!defined($$rHoSDDef{$element_name})) { printCEMsg("EMsgMCcliInvalidCmdArg", $element_name, $resource, '"' . $rNameValue->[0] . '"'); $badrc = MC_CLI_USER_ERROR; next; # continue validating rest of input } # Get the elements value $data_type = $rHoSDDef->{$element_name}{sd_dtype}; # An SD cannot contain an SD if ($data_type == CT_SD_PTR || $data_type == CT_SD_PTR_ARRAY) { my $dtype_str = data_type_to_string($data_type); printCEMsg("EMsgMCcliInvalidArgDataType", $resource, $element_name, $dtype_str); $rc = MC_CLI_USER_ERROR; } ($rc, $element_value) = convert_input_value($data_type, $new_element->[1]); if ($rc != 0) { printCEMsg("EMsgMCcliBadArgValue", $element_name, $new_element->[1]); if ($badrc == 0) {$badrc = $rc; } next; } $rHoSDDef->{$element_name}{sd_value} = $element_value; } # Get the list of all the input element names in element index # order. No guarantee that we got them from RMC in correct order # but we have to make sure we give them to RMC in the correct order. # Also even if RMC gave them in the correct order we stored them # in a hash and a hash does not guarantee any order. my @required_element_names = get_sd_element_names($rHoSDDef); # Make sure that all of the required elements are being # defined. foreach $element_name (@required_element_names) { if (!defined($$rHoSDDef{$element_name}{sd_value})) { printCEMsg("EMsgMCcliMissingReqArg", $element_name, $resource, $main::PROGNAME); $badrc = MC_CLI_USER_ERROR; } } # Create the structured data structure (an array of hashes # with the type and value - with one hash representing each # element in the SD. Make sure the order is correct.) my @LoSD = (); # Create the array # by-pass creating @LoSD if no args specified if ($#{$rNameValue->[1]} >=0) { foreach $element_name (@required_element_names) { my %element = (); $element{type} = $$rHoSDDef{$element_name}{sd_dtype}; $element{value} = $$rHoSDDef{$element_name}{sd_value}; push @LoSD, { %element }; } } return($badrc, @LoSD); } # end build_cmd_arg_sd #--------------------------------------------------------------------# # End Exported Subroutines (with @EXPORT_OK, -> on demand). # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # 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 rmc resource class 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, $response, $rmc_rc, $error) = @_; my $rc = 0; my $err_rc = $error->errnum(); if ($rmc_rc != 0) { if ($rmc_function eq "mc_qdef_sd_bp") { printCEMsg("EMsgMCcliQdefSDError", $rmc_class); } 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++) { if ($r > 0) { $response->error($error, $r); $err_rc = $error->errnum(); } if ($err_rc != 0) { if ($err_rc == CT::MCerr::RMC_ECLASSNOTDEFINED) { printCEMsg("EMsgMCcliClassNotDef", $rmc_class); $rc = MC_CLI_USER_ERROR; } elsif ($err_rc == CT::MCerr::RMC_EBADRSRCHANDLE || $err_rc == CT::RM::RM_EINVRESHANDLE || $err_rc == CT::RM::RM_EINVALIDHANDLE) { printCEMsg("EMsgMCcliInvalidRsrcHandle", $rmc_class); $rc = MC_CLI_USER_ERROR; } elsif ($err_rc == CT::MCerr::RMC_EACCESS) { print STDERR $error->error_msg; $rc = MC_CLI_USER_ERROR; } elsif ($err_rc == RMC_EBADACTIONNAM) { print STDERR $error->error_msg; $rc = MC_CLI_USER_ERROR; } # It is possible for Resource Class to have no Cmd Args # defined - this is not an error. elsif ($err_rc == RMC_ESDNOTDEFINED) { $rc = 0; } 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 { if ($rmc_function eq "mc_qdef_sd_bp") { printCEMsg("EMsgMCcliQdefSDError", $rmc_class); } 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 #--------------------------------------------------------------------# # End Non Exported Subroutines - only used within this pm. # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # End File. # #--------------------------------------------------------------------#