Edit D:\app\Administrator\product\11.2.0\dbhome_1\sysman\admin\scripts\has\HasCluster.pm
# Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. # # $Id: HasCluster.pm /stpl_db_11.2.0.1.0_gen/2 2009/11/25 12:05:32 ajdsouza Exp $ # # # NAME # HasCluster.pm # # DESC # Common cluster subroutines # # # FUNCTIONS # AUTOLOADER # # NOTES # # # MODIFIED (MM/DD/YY) # ajdsouza 11/14/09 - Bug fix#9117595 # ajdsouza 10/15/09 - Bug fix#9009918 # ajdsouza 10/07/09 - Bug fix#8988446 # ajdsouza 12/07/08 - Bug fix#7689615 # kramarat 06/09/08 - Siha support for Listener # ajdsouza 05/13/08 - # vgoli 03/24/08 - use JDBC/OCI wrappers # ajdsouza 01/23/07 - Created # # package has::HasCluster; use Exporter; use strict; use warnings; use locale; use File::Spec::Functions; use File::Path; use Data::Dumper; #this module is not available in emagent 10.2.0.4 my $hostNameSub = 'hostOSD::getHostName'; my $hostDomainSub = 'hostOSD::getDomainName'; eval "use hostOSD; 1 " or undef $hostNameSub and undef $hostDomainSub and warn "DEBUG:hostOSD perl module is not available"; use Sys::Hostname; use DBI; use XML::Parser; use FindBin; use Config; use has::Common; use has::sCommon; require "has/SQL.pl"; require "emd_common.pl"; require "semd_common.pl"; $Data::Dumper::Indent = 2; $Data::Dumper::Deepcopy = 1; $Data::Dumper::Purity = 1; $Data::Dumper::Sortkeys = 1; our @ISA = qw(Exporter); our @EXPORT = qw( ); #------------------------------------------------------------------------------ # global package variables #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # package level variables #----------------------------------------------------------------------------- # variables for xml related parsing my $has_xref; my $has_fref; #----------------------------------------------------------------------------- # sub routines #----------------------------------------------------------------------------- sub hasGetFunctionString($;@); sub readRegressionDatFile(); sub get_fn_results($); sub regression_test($$;@); sub hasInit(;$); sub hasCleanup(;$); sub runsystemcommand( $;$$ ); sub print_warn_message(@); sub print_error_message(@); sub exit_fail(@); sub hasGetXmlErrorStack(); sub get_error_stack(); sub has_handle_error(@); sub has_printerrors; sub save_systemcmdoutput(); sub has_start_handler; sub has_end_handler; sub has_char_handler; sub parse_xml($); sub traverse_xml($$$@); sub delete_element($); sub mark_depth($); sub append_element( $$ ); sub make_element ($;$$); sub print_xml($$); sub dump_xml($$); # Traverse the tree depth first based on the start and tag passed # and the specified order sub fntrdf( $$$$\&$;$$$ ); # Traverse the tree breadth first based on the start and tag passed # and the specified order sub fntrbf( $$$$\&$; ); sub has_get_cache_dir (); sub hasDoesFileExist($;); sub hasIsReadable($;); sub hasIsWriteable($;); sub hasIsDir($;); sub hasReturnFileContents($;$); sub hasWriteToFile($$$;); sub hasSetCRSEnv(;$); sub hasRestoreCRSEnv(); sub hasGetEnv(); sub hasGetNodeCRSHome(;$$); sub hasGetCRSHome(;$); sub hasGetEnvCRSHome(); sub hasGetOSLocalHostName(); sub hasGetLocalHostName(); sub hasGetDomainName(;$); sub hasCheckForEmcrsp($); sub hasGetEntityInformation($;$$); sub hasDiscoverCluster(;$); sub hasIsVendorClusterware($); sub hasSearchClusterName(;$); sub hasCemutloClusterName($); sub hasCemutlsClusterName($); sub hasGetClusterConfigPre11g(;$$); sub hasGetClusterNodeListPre11g(;$); sub hasGetClusterGetNodeNamePre11g(;$); sub hasGetClusterConfigEmcrsp(;$); sub hasGetClusterStatus( $;$$ ); sub getClusterCacheRef(); sub clusterConfigCopyVals($$;); sub hasGetClusterConfig(;$$); sub hasGetClusterName(;$$); sub hasGetNodeList(;$); sub hasGetNodeStatus(;$$); sub hasGetNodeName(;$); sub hasGetClusterVersion(;$$); sub hasGetClusterVendor(;$$); sub hasGetClusterActiveVersion(;$$); sub hasGetIsVendorCluster(;$$); sub hasGetOcrType(;$$); sub hasGetClusterNodes(;$); sub hasGetScanInformation(;$); sub hasClusterHealthCheck($;$); sub hasGetScanVIPInformation(;$); sub hasGetScanName(;$); sub hasGetScanIP(;$); sub hasGetScanPort(;$); sub hasGetEONSInformation(;$); sub hasGetEONSPort(;$); sub hasGetVotingDiskInformation(;$); sub hasGetOCRInformation(;$); #sub hasGetSQLResults($;$); sub hasGetDBResourceInformation($); sub hasIsDBManagedByHas($$$$;$$$); sub hasIsLsnrManagedByHas($$;$); sub hasCheckAndReturnEmcrspResults($); sub hasadm_resource_types_mark_base_types($); sub hasGetResourceNameForOracleApp($$;$$); sub hasListenerGetScanName($;$); sub hasIsListenerScan($;$); sub has_dependencies($$$); sub has_em_results ($$$;$); sub has_gen_key_value($$;); sub has_entity_fn($$$;@); sub has_gpnp_server_pool_fn($$$;@); sub has_resource_crs_servers_fn($$$;@); sub fnnpprnd ( $$$$$ ); sub fnnpprdp ( $$$$$ ); sub fnnpprnb ( $$$ ); sub hasGetResourceDependencyString($;); sub hasGetResourceDependents($;); #------------------------------------------------------------------------------- # FUNCTION : hasGetFunctionString # # DESC # return the string for function name + arguments # # ARGUMENTS # sub name # reference to the sub to be executed # reference to the list of arguments to the sub # #------------------------------------------------------------------------------- sub hasGetFunctionString($;@) { # my ($sub,$array_ref) = @_; my ($sub,@args) = @_; #my @args; #@args = @$array_ref if $array_ref and ref($array_ref) and ref($array_ref) =~ /LIST/; #@args = $array_ref if $array_ref and ref($array_ref) and ref($array_ref) =~ /SCALAR/; warn "WARN:has::Common::hasGetFunctionString No function name passed for regression" and return unless $sub; #----------------------------------------------------------------------------- # Start Regression or capture #----------------------------------------------------------------------------- # create a mangled name for capture and regression test mode my $function_name = "fn_"; # use the interface name to build the function string # helps during multiple shell invocations if they need different tests map { my $element_value = $_; $element_value =~ s/\s+//g if $element_value; undef $element_value if $element_value and $element_value =~ /^\s*$/; if ( not $element_value ) { $function_name = "$function_name\_null"; } else { $function_name = "$function_name\_$element_value"; } } @has::Common::iface if @has::Common::iface; $function_name = "$function_name\_$sub"; # mangle the arguments into a function_name to be saved as a file # for non scalar refs, put the ref type and not the address # the function counter will take care of opening the right file # durign regression map { my $element_value = $_; $element_value =~ s/\s+//g if $element_value; undef $element_value if $element_value and $element_value =~ /^\s*$/; if ( not $element_value ) { $function_name = "$function_name\_null"; } else { my $ref_type = ref($element_value) if $element_value; if ( not $ref_type ) { $function_name = "$function_name\_$element_value"; } elsif ( $ref_type =~ /SCALAR/i ) { $function_name = "$function_name\_$$element_value"; } else { my $dmpstrg; $dmpstrg = Dumper($ref_type); $dmpstrg='' unless $dmpstrg; $function_name = "$function_name\_$dmpstrg"; } } } @args if @args; # Remove these special characters from the file name $function_name =~ s/\n/_nl_/g; $function_name =~ s/\@/_a_/g; $function_name =~ s/\&/_am_/g; $function_name =~ s/\*/_as_/g; $function_name =~ s/\\/_b_/g; $function_name =~ s/\(|\)|{|}|\[|\]/_br_/g; $function_name =~ s/\^/_c_/g; $function_name =~ s/\$/_d_/g; $function_name =~ s/\./_do_/g; $function_name =~ s/\!/_e_/g; $function_name =~ s/\`/_es_/g; $function_name =~ s/\=/_eq_/g; $function_name =~ s/\\|\//_fs_/g; $function_name =~ s/\#/_h_/g; $function_name =~ s/\-/_hf_/g; $function_name =~ s/\n/_nl_/g; $function_name =~ s/\+/_p_/g; $function_name =~ s/\|/_pp_/g; $function_name =~ s/\s+/_s_/g; $function_name =~ s/\~/_t_/g; $function_name =~ s/\,/_cm_/g; $function_name =~ s/\:/_sc_/g; warn "WARN:has::Common::hasGetFunctionString Failed to generate a function signature for sub $sub \n" and return unless $function_name; # Appened a count to the function name # The same function may be invoked multiple times with # different results $has::Common::regression_fn_count{$function_name}=0 unless $has::Common::regression_fn_count{$function_name}; $has::Common::regression_fn_count{$function_name}++; $function_name = "$function_name\_cnt\_$has::Common::regression_fn_count{$function_name}"; return $function_name; } #------------------------------------------------------------------------------- # FUNCTION : readRegressionDatFile() # # DESC : # read the contents of te regression/capture dat file and cache values to # hash variable %has::Common::has_test_res_ref # # ARGS : # #------------------------------------------------------------------------------- sub readRegressionDatFile() { if ( $has::Common::has_test_res_ref ) { return $has::Common::has_test_res_ref; } my $has_result_fpath; $has_result_fpath = $ENV{HAS_TEST_FILE_PATH} if $ENV{HAS_TEST_FILE_PATH}; $has_result_fpath = File::Spec->catfile(File::Spec->tmpdir(), $has::Common::has_test_res_filen) unless $has_result_fpath; stat($has_result_fpath); warn "WARN:has::Common::readRegressionDatFile File $has_result_fpath for persisting command results is not accessible\n" and return unless -e $has_result_fpath and -r $has_result_fpath; $has::Common::has_test_res_ref = do "$has_result_fpath"; warn "WARN:has::Common::readRegressionDatFile Failed to read the captured test results from file $has_result_fpath\n" and return unless ( $has::Common::has_test_res_ref and ref($has::Common::has_test_res_ref) =~ /HASH/i and keys %{$has::Common::has_test_res_ref} ); return $has::Common::has_test_res_ref; } #------------------------------------------------------------------------------- # FUNCTION : get_fn_results($) # # DESC : # return the captured results for a function call # # ARGS : # $ - mangled interface name # #------------------------------------------------------------------------------- sub get_fn_results($) { my ($interface_name) = @_; #$interface_name =~ s/\s+//; warn "WARN:has::Common::get_fn_results Interface name expected as arg in get_fn_results\n" and return unless $interface_name; #$interface_name =~ s/\./_dt_/g; my $intfcachref = has::Common::readRegressionDatFile(); warn "WARN:has::Common::get_fn_results Failed to find the interface name $interface_name \n" and return unless $intfcachref and ref($intfcachref) and defined $intfcachref->{$interface_name}; my $fnresults = $intfcachref->{$interface_name}; my $VAR1; eval $fnresults or warn "WARN:has::Common::get_fn_results Failed to eval results for interface $interface_name\n" and return; return $VAR1; } #------------------------------------------------------------------------------- # FUNCTION : regression_test # # DESC # Perform a capture for regression test, or perform a regression_test # Specified by enironment variables # # ARGUMENTS # sub name # reference to the sub to be executed # reference to the list of arguments to the sub # #------------------------------------------------------------------------------- sub regression_test($$;@) { #my ($sub,$sub_ref,$array_ref) = @_; my ($sub,$sub_ref,@args) = @_; warn "WARN::has::Common::regression_test Subroutine name for regression is null" and return unless $sub; #my @args = @$array_ref; #----------------------------------------------------------------------------- # fall thru below this line only for test mode # either REGRESSION or CAPTURE #----------------------------------------------------------------------------- # The test mode validation warn "WARN:has::Common:: regression_test Unknown run mode can be REGRESSION or CAPTURE\n" and return unless $ENV{HAS_TEST_MODE} and $ENV{HAS_TEST_MODE} =~ /REGRESSION|CAPTURE/i; #----------------------------------------------------------------------------- # Start Regression or capture #----------------------------------------------------------------------------- # create a mangled name for capture and regression test mode my $function_name; $function_name = has::Common::hasGetFunctionString($sub,@args); #$function_name = has::Common::hasGetFunctionString($sub,$array_ref); warn "WARN::has::Common::regression_test Function name for regression is null" and return unless $function_name; #------------------------------------------------------------ # If test regression mode read from stored file and return # results #------------------------------------------------------------ if ( $ENV{HAS_TEST_MODE} =~ /REGRESSION/i ) { # no results expected, execute the function and return return &$sub_ref(@args) if not defined wantarray; my $result_ref = has::Common::get_fn_results($function_name); return unless $result_ref; # results expected is a list if ( wantarray ) { return @$result_ref; } else { # result expected is a scalar or # a reference to a list my $ref_type = ref($result_ref); # if the result read is a reference to a scalar, # return scalar value return $$result_ref if $ref_type =~ /SCALAR/i; # if result read is a ref to a list , return reference return $result_ref; } } #------------------------------------------------------ # fall thru below this line only If test capture mode #------------------------------------------------------ # no results expected, so nothing to capture, # execute the subroutine and return #return &$sub_ref(@args) if not defined wantarray; #------------------------------------------------------ # fall thru below this line only If return value is # expected #------------------------------------------------------ # If an list result is expected if ( wantarray ) { my @results_array = &$sub_ref(@args); # Store the results #return 1 if $has::Common::has_test_res_ref->{$function_name}; return @results_array if $has::Common::has_test_res_ref->{$function_name}; my $dumped_results; if ( \@results_array ) { $dumped_results = Dumper(\@results_array) or warn "WARN::has::Common::regression_test Failed to save results for function $function_name\n" and return; } $has::Common::has_test_res_ref->{$function_name} = $dumped_results if $dumped_results; $has::Common::has_test_res_ref->{$function_name} = undef unless $dumped_results; # return the results return @results_array; } else # an scalar result is expected # scalar could be an reference to a list { my $results_ref = &$sub_ref(@args); my $store_results_ref = $results_ref; # if result is not a ref # take a pointer to the scalar # to store results my $ref_type = ref($results_ref); $store_results_ref = \$results_ref unless $ref_type; # Store the results #return 1 if $has::Common::has_test_res_ref->{$function_name}; if ( not defined $has::Common::has_test_res_ref->{$function_name} ) { my $dumped_results; if ( $store_results_ref ) { $dumped_results = Dumper($store_results_ref) or warn "WARN:has::Common::regression_test Failed to save results for function $function_name\n" and return; } $has::Common::has_test_res_ref->{$function_name} = $dumped_results if $dumped_results; $has::Common::has_test_res_ref->{$function_name} = undef unless $dumped_results; } # return the results return $results_ref if $results_ref; return; } } #------------------------------------------------------------------------------ # FUNCTION : hasInit # # DESC # do initialization before using library # should be called explicityly by calling function # # ARGUMENTS # crsHome # # RETURNS # #------------------------------------------------------------------------------ sub hasInit(;$) { my ( $crsHome ) = @_; has::Common::hasCleanup($crsHome); $Data::Dumper::Indent = 2; $Data::Dumper::Deepcopy = 1; my $xml_error_ref = has::Common::make_element('errors'); undef %has::Common::has_xml_errors; %has::Common::has_xml_errors = %{$xml_error_ref}; return 1; } #------------------------------------------------------------------------------ # FUNCTION : hasCleanup # # DESC # do cleanup before leaving library # should be called explicityly by calling function # # ARGUMENTS # crsHome # # RETURNS # #------------------------------------------------------------------------------ sub hasCleanup(;$) { my ( $crsHome ) = @_; %has::Common::hasClusterConfig = (); @has::Common::oldOH = (); @has::Common::oldCRSHome = (); @has::Common::oldEMCRSHome = (); # cleanup errr stack from previous run %has::Common::has_error_stack = (); %has::Common::has_xml_errors = (); # hash variables to keep track of base resource type, attrrib base type # resource instance - resource name # internal resource types %has::Common::hasadm_restype_base = (); %has::Common::hasadm_restype_attrib = (); %has::Common::hasadm_resource_type_list = (); %has::Common::hasadm_resource_list = (); %has::Common::hasadm_resourceinst_list = (); %has::Common::hasadm_list_internalresource_types = (); return 1; } #------------------------------------------------------------------------------ # FUNCTION : runsystemcommand($;$$) # # DESC # Run a system command , retry n times if it times out # # ARGUMENTS # command to be executed ( e.g. crsctl start crs ) # variable args to the command ( eg nodename) # a hash ref with # {timeout} in seconds, default 120 # {tries} no of tries , default 2. # {timeout_return} flag 1 to indicate if function should return # in case of timeout, default is to die # {exit_failure_list} # {exit_success_list} # The lists to indicate failure and sucess exit status if they are other # than 0=Success all other exit status are =Fail # You can define one of the list of both the lists # e.g. for 'crsctl start crs' # {exit_failure_list}=[(1,3,5,6)] # {exit_success_list}=[(0,2)] # # RETURNS: # result set either an array or a arg # the $? for the os command as {command_return_status} of the hash ref arg # {command_error_message} returns $! $@ # #------------------------------------------------------------------------------ sub runsystemcommand( $;$$ ) { my ($fullcmd,$args,$argref) = @_; # fix for bug 6261302 # go over path and get the full path to the variable # Not reqd to do this in regression or capture mode when # ENV{HAS_TEST_MODE} = capture or regression return has::sCommon::runsystemcommand($fullcmd,$args,$argref) if $ENV{HAS_TEST_MODE} and $ENV{HAS_TEST_MODE} =~ /capture|regression/i; my $cmd; my $cmdargs; #split any args from command ($cmd,$cmdargs) = ( $fullcmd =~ /^([^\s]+) (.*)/ ); $cmd = $fullcmd and undef $cmdargs unless $cmd; $cmd =~ s/^\s+//g if $cmd; # $cmd is asolute path , invoke runsystemcommand return has::sCommon::runsystemcommand($fullcmd,$args,$argref) if has::Common::hasIsReadable($cmd); # command does not have path figure out path from env variable my @paths; my $fullpath; @paths = File::Spec->path(); # on windows get the appended path if ( $^O =~ /windows|mswin/i ) { if ( @paths and $paths[0] ) { # Bug fix#9117595 # with perl 5.10 if command is prepended then first in path array is '.' my $pathtosplit = $paths[0]; $pathtosplit =~ s/^\s+|\s+$//; if ( ( not $pathtosplit or $pathtosplit !~ /:(?!(\\|\/))/ ) and @paths > 1 and $paths[1] ) { $pathtosplit = $paths[1]; $pathtosplit =~ s/^\s+|\s+$//; } my @setpaths = split/:(?!(\\|\/))/,$pathtosplit if $pathtosplit and $pathtosplit =~ /:(?!(\\|\/))/; if ( @setpaths ) { my @newsetpath; for my $setpath ( @setpaths ) { next unless $setpath; push @newsetpath,$setpath; } @setpaths = @newsetpath; } if ( @setpaths ) { #shift @paths; unshift @paths,@setpaths; } } } for my $path ( @paths ) { for my $extn ( ( '', '.exe', '.bat' ) ) { my $tcmd = "$cmd$extn"; $fullpath = catfile($path,$tcmd); last if has::Common::hasIsReadable($fullpath); undef $fullpath; next; } last if $fullpath; } $fullpath = "$fullpath $cmdargs" if $fullpath and $cmdargs; $fullpath = $fullcmd unless $fullpath; return has::sCommon::runsystemcommand($fullpath,$args,$argref); } #------------------------------------------------------------------------------ # FUNCTION : print_warn_message # # DESC # print warning messages # # ARGUMENTS # message #------------------------------------------------------------------------------ sub print_warn_message(@) { my ( $message ) = @_; chomp $message; $message =~ s/\n/ /g if $message; $message =~ s/^\s+|\s+$// if $message; $message = '' unless $message; # log the message to the log file EMD_PERL_WARN("WARN:Warning message from script $message"); # send the warning message to emagent print "em_warning=Warning message from script $message\n"; return 1; } #------------------------------------------------------------------------------ # FUNCTION : print_error_message # # DESC # print error messages # # ARGUMENTS # message #------------------------------------------------------------------------------ sub print_error_message(@) { my ( $message ) = @_; chomp $message; $message =~ s/\n/ /g if $message; $message =~ s/^\s+|\s+$// if $message; $message = '' unless $message; # log the message to the log file EMD_PERL_ERROR("ERROR:Error message from script $message"); # send the warning message to emagent print "em_error=Error message from script $message\n"; return 1; } #------------------------------------------------------------------------------ # FUNCTION : exit_fail # # DESC # clean up, print errors before failure exit # # ARGUMENTS # message #------------------------------------------------------------------------------ sub exit_fail(@) { my ( $message ) = @_; print_error_message($message); exit 1; } #------------------------------------------------------------------------------ # FUNCTION : hasGetXmlErrorStack # # DESC # returns an ref to the has xml error stack # # ARGUMENTS # #------------------------------------------------------------------------------ sub hasGetXmlErrorStack() { return \%has::Common::has_xml_errors; } #------------------------------------------------------------------------------ # FUNCTION : get_error_stack # # DESC # returns an ref to the has error stack # # ARGUMENTS # #------------------------------------------------------------------------------ sub get_error_stack() { return \%has::Common::has_error_stack; } #------------------------------------------------------------------------------ # FUNCTION : has_handle_error # # DESC # log the message to trace and for error and warn keep it in the stack to be # printed at the end # # ARGUMENTS # message #------------------------------------------------------------------------------ #---------------------------------------------------------------------------- # SIGNAL handler for die and warn to Log error and warning messages #---------------------------------------------------------------------------- # die will exit the program with a warn message sub has_handle_error(@) { my ( $message ) = @_; my $mtype; chomp $message if $message; $message =~ s/^\s+|\s+$// if $message; return unless $message; # log only errors to the em respository, ignore debug and trace messages ( $mtype, $message ) = ( $message =~ /^(ERROR|WARN|DEBUG|INFO)\s*:\s*(.+)/i ) if $message =~ /^(ERROR|WARN|DEBUG|INFO)\s*:/i; $message =~ s/^\s+|\s+$// if $message; $mtype =~ s/^\s+|\s+$// if $mtype; # c executable has :: between error and message , so remove the extra : #$message =~ s/^:+// if $message; # log the message to the log file if ( $mtype and $mtype =~ /WARN/i and $message ) { EMD_PERL_WARN("WARN:has::Common:: $message"); } elsif ( $mtype and $mtype =~ /DEBUG/i and $message ) { EMD_PERL_DEBUG("DEBUG:has::Common:: $message"); } elsif ( $mtype and $mtype =~ /INFO/i and $message ) { EMD_PERL_INFO("INFO:has::Common:: $message"); } elsif ( $mtype and $mtype =~ /ERROR/i and $message ) { EMD_PERL_ERROR("ERROR:has::Common:: $message"); } elsif ( $message ) { EMD_PERL_ERROR("ERROR:has::Common:: $message"); } $mtype = 'ERROR' unless $mtype; return 1 unless $mtype and $mtype =~ /ERROR|WARN/i and $message; # Log a message only once return 1 if $has::Common::has_error_stack{$mtype}{$message}; $has::Common::has_error_stack{$mtype}{$message}=1; # maintain the serial order of the messages my $no_of_messages = keys %{$has::Common::has_error_stack{$mtype}}; $has::Common::has_error_stack{$mtype}{$message}=$no_of_messages; # also store the error as xml my $errref = has::Common::make_element('error'); my $etyperef = has::Common::make_element('type',$mtype); my $emsgref = has::Common::make_element('message',$message); has::Common::append_element($errref,$etyperef); has::Common::append_element($errref,$emsgref); has::Common::append_element(\%has::Common::has_xml_errors,$errref); return 1; } #------------------------------------------------------------------------------ # FUNCTION : has_printerrors # # DESC # print the errors with seperators # # ARGUMENTS # exit_type optional values fail|exit_fail|success # #------------------------------------------------------------------------------ sub has_printerrors { my ( $exit_type ) = @_; my $em_err_type; $em_err_type = 'em_error' if $exit_type and $exit_type =~ /fail/i; $em_err_type = 'em_warning' unless $em_err_type; my $errstackref; $errstackref = has::Common::get_error_stack(); return 1 unless $errstackref and ref($errstackref); for my $mtype ( qw ( ERROR WARN ) ) { next unless $errstackref->{$mtype}; # sort by the message serial num asc for my $msg ( sort { $errstackref->{$mtype}{$a} <=> $errstackref->{$mtype}{$b}} keys%{$errstackref->{$mtype}} ) { next unless $msg; chomp $msg; $msg =~ s/^\s+|\s+$//g; next unless $msg; print "$em_err_type=$mtype|$msg\n"; } } return 1; } #------------------------------------------------------------------------------ # FUNCTION : save_systemcmdoutput # # DESC # save the comd output from os commandinvoked thru runsystemcommand # to an os file - can be used for regression tests # # ARGUMENTS # #------------------------------------------------------------------------------ sub save_systemcmdoutput() { return 1 unless $ENV{HAS_TEST_MODE} and $ENV{HAS_TEST_MODE} =~ /CAPTURE/i; $has::Common::has_test_res_ref->{test_description} = $ENV{HAS_TEST_MODE_DESC} if $ENV{HAS_TEST_MODE_DESC}; my $thewholestrg = Dumper($has::Common::has_test_res_ref) or warn "WARN::has::Common::save_systemcmdoutput Failed to save the results for test $has::Common::has_test_res_ref\n" and return; my $test_file = catfile(File::Spec->tmpdir(),$has::Common::has_test_res_filen); stat($test_file); warn "WARN::has::Common::save_systemcmdoutput File $test_file for captured regression test data is not accessible\n" and return if -e $test_file and not -w $test_file; open(TFH,">$test_file") or warn "WARN::has::Common::save_systemcmdoutput Failed to open file $test_file for capturing test results \n" and return; print TFH $thewholestrg; close(TFH); return 1; } # name : has_start_handler # desc : handler to be invoked by perl parser when starting an element # # arg : # to be passed by the perl parser sub has_start_handler { my ($pr,$el,%attrs) = @_; $pr->{cdata_buffer} = ''; my %ehash = (element=>$el); $has_fref = \%ehash unless $has_fref; for my $name ( keys %attrs ) { $ehash{attrs}{$name}=$attrs{$name}; } $ehash{parent} = $has_xref if $has_xref; $ehash{depth} = $ehash{parent}->{depth}+1 if $ehash{parent}; $ehash{depth} = 0 unless $ehash{depth}; push @{$has_xref->{child_elements}{$el}},\%ehash if $has_xref; push @{$has_xref->{children}},\%ehash if $has_xref; $has_xref = \%ehash; } # name : has_end_handler # desc : handler function for perl parser when element closes # # arg : # passed by perl parser sub has_end_handler { my ($pr,$el) = @_; $has_xref = $has_xref->{parent}; } # name : has_char_handler # desc : handler function for perl parser for char # # arg # passed by parser # sub has_char_handler { my ($pr,$tag) = @_; $has_xref->{name}=$tag unless $has_xref->{name}; $has_xref->{name} =~ s/^\s|\s+$//g; chomp $has_xref->{name}; # delete $has_xref->{name} unless $has_xref->{name}; } # name : has_parse_xml # desc : parse a xml string to a perl variable # # arg : # xml string to be parsed # # return: # hash of parsed perl variable # sub parse_xml($) { my ( $result ) = @_; warn "WARN:has::Common::parse_xml No XML content to parse" and return unless $result; my $p = new XML::Parser(ErrorContext => 2, ProtocolEncoding => 'UTF-8', ); $p->setHandlers(Start => \&has_start_handler, End => \&has_end_handler, Char => \&has_char_handler); undef $has_fref; undef $has_xref; # save the signal handler defined for die my $diesh = $SIG{__DIE__} if $SIG{__DIE__}; # remove any signal handler defined for die $SIG{__DIE__}=''; eval{ $p->parse($result) }; # restore back the original die signal handler $SIG{__DIE__} = $diesh if $diesh; die "ERROR:has::Common::parse_xml $@ Failed to Parse $result\n" if $@ and $result; die "ERROR:has::Common::parse_xml $@ Failed to Parse \n" if $@; return %$has_fref; } # name : traverse_xml # desc : traverse the xml tree, execute specificed function for each element # # args : # ref to hash of root of xml # ref to error handlig function # ref to traverse function # ref to list of args to function # #sub traverse_xml(\%\&\&@) sub traverse_xml($$$@) { my ( $xmlref,$fnerrhndl,$fnref,@args) = @_; my @stack; # to print the array depth first push @stack, $xmlref if $xmlref; while ( my $xref = pop @stack ) { next unless $xref; # keep error messages in the error stack #<errors> # <error> # <type>error|warn</type> # <message>error_message</message> # </error> #</errors> if ( $xref->{element} and $xref->{element} =~ /^error$/i and $xref->{children} ) { my $mtype; my $message; for my $ec ( @{$xref->{children}} ) { $mtype = $ec->{name} if $ec->{element} =~ /^type$/i and $ec->{name}; $message = $ec->{name} if $ec->{element} =~ /^message$/i and $ec->{name}; } &{$fnerrhndl}("$mtype:$message") if $mtype and $message and $fnerrhndl; } # keep error messages in the error stack for opcode != 0 #<opcode> # <code>0</code> # <message>Succcess</message> #</opcode> elsif ( $xref->{element} and $xref->{element} =~ /^opcode$/i and $xref->{children} ) { my $code; my $mtype; my $message; my $emessage; for my $ec ( @{$xref->{children}} ) { $code = $ec->{name} if $ec->{element} =~ /^code$/i and $ec->{name}; $message = $ec->{name} if $ec->{element} =~ /^message$/i and $ec->{name}; } # if code != 0 indicates a failure for that element if ( $code ) { $mtype = 'WARN'; #a failure of a step is a warning as other steps might have succeeded my $entity_name; my $entity_type; my $parent_ref = $xref->{parent} if $xref->{parent}; if ( $parent_ref and $parent_ref->{attrs} ) { $entity_name = $parent_ref->{attrs}{entity_name} if $parent_ref->{attrs}{entity_name}; $entity_type = $parent_ref->{attrs}{entity_type} if $parent_ref->{attrs}{entity_type}; $emessage = "for $entity_type $entity_name" if $entity_type and $entity_name; $emessage = "for $entity_type" if $entity_type and not $emessage; $emessage = "for $entity_name" if $entity_name and not $emessage; } $message = "$message $emessage" if $message and $emessage; $message = "Failed $emessage" if $emessage and not $message; $message = "Failed" unless $message; &{$fnerrhndl}("$mtype:$message") if $mtype and $message and $fnerrhndl; } } # keep error messages in the error stack for return code != 0 #<returncode> # <code>0</code> # <mesg>Succcess</mesg> #</returncode> elsif ( $xref->{element} and $xref->{element} =~ /^returncode$/i and $xref->{children} ) { my $code; my $mtype; my $message; for my $ec ( @{$xref->{children}} ) { $code = $ec->{name} if $ec->{element} =~ /^code$/i and $ec->{name}; $message = $ec->{name} if $ec->{element} =~ /^mesg$/i and $ec->{name}; } # if code != 0 indicates a failure for that element if ( $code ) { $mtype = 'ERROR'; #a failure overall is an ERROR $message = "Failed" unless $message; &{$fnerrhndl}("$mtype:$message") if $mtype and $message and $fnerrhndl; } } # execute function for each element &{$fnref}($xref,@args) or die "ERROR:has::Common::traverse_xml Failed to execute function\n"; next if $xref->{ignore}; push @stack, reverse @{$xref->{children}} if $xref->{children}; } return 1; } # name : delete_element # desc : delete a element , remove it from the xml tree # # arg : # ref to the hash of the element to be removed sub delete_element($) { my ($elref) = @_; # mark it to be ignored $elref->{ignore}=1; # delete its children delete $elref->{children} if $elref->{children}; delete $elref->{child_elements} if $elref->{child_elements}; # delete it from the parent elements if ( $elref->{parent} and $elref->{parent}->{child_elements} and $elref->{parent}->{child_elements}{$elref->{element}} ) { my @child_elements = @{$elref->{parent}->{child_elements}{$elref->{element}}}; for my $i ( 0..@child_elements ) { splice @{$elref->{parent}->{child_elements}{$elref->{element}}}, $i,1 if $child_elements[$i] == $elref; } } if ( $elref->{parent} and $elref->{parent}->{children} ) { my @child_elements = @{$elref->{parent}->{children}}; for my $i ( 0..@child_elements ) { splice @{$elref->{parent}->{children}},$i,1 if $child_elements[$i] == $elref; } } %{$elref}=(); undef %{$elref}; return 1; } # name : mark_depth # desc : mark depth of each element in xml var # # arg # ref to hash of parent var # sub mark_depth($) { my ( $elref ) = @_; die "ERROR: Parent node has no depth defined for ".Dumper($elref) if $elref->{parent} and $elref->{parent}->{depth} !~ /\d+/; $elref->{depth} = $elref->{parent}->{depth} + 1 if $elref->{parent}; $elref->{depth} = 0 unless $elref->{depth}; return 1; } # name : append_element # desc append element # # args # ref to parent # ref to child # return: # ref to parent sub append_element( $$ ) { my ( $pref, $cref ) = @_; push @{$pref->{children}},$cref; push @{$pref->{child_elements}{$cref->{element}}},$cref; $cref->{parent} = $pref; return $pref; } # name : make_element # make a new element # # args: # element # value # ref to attributes array # return: # ref to hash of the new element sub make_element ($;$$) { my ( $elem, $name, $attrs_ref ) = @_; my %element; $element{element} = $elem; $element{name} = $name if $name; $element{name} = undef unless $element{name}; return \%element unless $attrs_ref and ref($attrs_ref) =~ /HASH/i and keys %{$attrs_ref}; for my $attr ( keys %{$attrs_ref} ) { $element{attrs}{$attr} = $attrs_ref->{$attr} if $attr; } return \%element; } # name : print_xml # desc : print formatted xml from xml variable # # args : # xml doc type header # ref to hash of root element # sub print_xml($$) { my ( $has_xml_doctype,$xmlref ) = @_; my $xmlstrg = has::Common::dump_xml($has_xml_doctype,$xmlref); print "$xmlstrg"; return 1; } # name : dump_xml # desc : dump formatted xml from xml variable to string # # args : # xml doc type header # ref to hash of root element # # returns: # xml dumped to a string # sub dump_xml($$) { my ( $has_xml_doctype,$xmlref ) = @_; my @stack; my %to_close_at; my $xmlstring = ''; # to close the element sub close_elements( \%\@$$ ) { my ($tca_ref,$s_ref,$xref,$xmlstring) = @_; # before printing the current element,close any elements that # are to be closed for my $dpth ( sort {$b <=> $a} keys %{$tca_ref} ) { last unless $dpth >= $xref->{depth}; for my $stk( sort {$b <=> $a} keys %{${$tca_ref}{$dpth}} ) { last unless $stk >= @{$s_ref}; my $temp = sprintf("%*s</${$tca_ref}{$dpth}{$stk}>\n",$dpth,' '); $xmlstring= "$xmlstring$temp" if $temp; delete ${$tca_ref}{$dpth}{$stk}; } delete ${$tca_ref}{$dpth}; } return $xmlstring; } # make sure the depth is marked for each element as it is required for indenting has::Common::traverse_xml($xmlref,\&has::Common::has_handle_error,\&has::Common::mark_depth); $xmlstring = "$has_xml_doctype\n"; # to print the array depth first push @stack, $xmlref; while ( my $xref = pop @stack ) { next unless $xref; $xref->{depth} = 0 unless defined $xref->{depth}; $xmlstring=close_elements(%to_close_at,@stack,$xref,$xmlstring); my $temp = ''; $temp = sprintf("%*s<",$xref->{depth},' '); $temp = "$temp$xref->{element}" if $xref->{element}; $temp = $temp.'UNKNOWN' unless $xref->{element}; # open element $xmlstring = "$xmlstring$temp" if $temp; # print attributes for my $attr ( keys %{$xref->{attrs}} ) { $xmlstring = "$xmlstring $attr=\'$xref->{attrs}{$attr}\'"; } $xmlstring = "$xmlstring>"; $xmlstring = "$xmlstring$xref->{name}" if defined $xref->{name}; if ( $xref->{children} ) { $xmlstring = "$xmlstring\n"; $to_close_at{$xref->{depth}}{@stack}=$xref->{element}; push @stack, reverse @{$xref->{children}}; } else { $xmlstring = "$xmlstring</$xref->{element}>\n" if $xref->{element}; $xmlstring = "$xmlstring</UNKNOWN>\n" unless $xref->{element}; } } $xmlstring=close_elements(%to_close_at,@stack,$xmlref,$xmlstring); return $xmlstring; } #------------------------------------------------------------------------------ # FUNCTION : fntrdf # # DESC # Traverse the tree based on the start and tag passed # and the specified order # # ARGUMENTS # order - preorder,postorder # node # traverse tag # key index # print fn or any other fn to act on each node # ref to the print string # # RETURNS # #------------------------------------------------------------------------------ sub fntrdf( $$$$\&$;$$$ ) { my ($order,$node, $tvtag, $iekv, $fnptr,$strg_ref,$stack_ref,$has_clpstk,$has_indnthsh) = @_; # This is a closed loop, the stack keeps track of the node # pointers already traversed if ( $has_clpstk and $has_clpstk->{$tvtag}{$node} ) { warn "WARN:has::Common::fntrdf:Node $node->{resource} $node->{entity_type} is in a closed loop when traversing $tvtag\n "; return 1; } # mark the node as traversed if previously not marked so # this will help identify nodes which are in completely closed # loops $node->{traversed}=1 unless $node->{traversed}; # the depth of the tree at any point # is the size of the stack my $depth = keys %{$stack_ref}; $depth +=1; $stack_ref->{$depth}=$node; # keep an index of the node pointer , for closed loop check $has_clpstk->{$tvtag}{$node}=1; my @kvs; my $node_count = 0; # traverse each child node specified by the traverse_tag if ( defined $node->{$tvtag} and $node->{$tvtag} and ref($node->{$tvtag}) =~ /HASH/i and keys %{$node->{$tvtag}} ) { # List of keys from this node to traverse in the direction # specified by traverse tag @kvs = sort { $iekv->{$a}->{type} cmp $iekv->{$b}->{type} } keys %{$node->{$tvtag}}; # count of nodes to travserse from this node $node_count = @kvs; } $has_indnthsh->{$depth}=$node_count; # preorder processing if ( $order =~ /preorder/i) { if ( $fnptr ) { # Execute the function to execute before traversing down the tree if ( not $fnptr->($node, $tvtag, $stack_ref, $strg_ref,$has_indnthsh) ) { delete $stack_ref->{$depth}; delete $has_clpstk->{$tvtag}{$node}; return; } } } # traverse each child node specified by the traverse_tag if ( @kvs ) { for my $i ( 1..$node_count ) { my $kv = $kvs[$i-1]; next unless $kv; warn "WARN:has::Common::fntrdf:Failed to find the storage entity $kv in the indexed list\n" and return unless $iekv->{$kv}; my $next_node = $iekv->{$kv}; next unless $next_node; bless $next_node; # keeps track of the pending children at any # depth in the layout $has_indnthsh->{$depth} = $node_count-$i; if ( not fntrdf ( $order, $next_node, $tvtag, $iekv, &$fnptr, $strg_ref, $stack_ref, $has_clpstk, $has_indnthsh ) ) { # unwind the stack and the closed loop index delete $stack_ref->{$depth}; delete $has_clpstk->{$tvtag}{$node}; return; } } } # postorder processing if ( $order =~ /postorder/i) { if ( $fnptr ) { # Execute the function to execute before traversing down the tree if ( not $fnptr->($node, $tvtag, $stack_ref,$strg_ref,$has_indnthsh ) ) { delete $stack_ref->{$depth}; delete $has_clpstk->{$tvtag}{$node}; return; } } } # unwind the stack and the closed loop index delete $stack_ref->{$depth}; delete $has_clpstk->{$tvtag}{$node}; return 1; } #------------------------------------------------------------------------------ # FUNCTION : fntrbf # # DESC # Traverse the tree based on the start and tag passed # and the specified order # # ARGUMENTS # order - preorder,postorder # node # traverse tag # key index # print fn or any other fn to act on each node # ref to the result hash # # RETURNS # #------------------------------------------------------------------------------ sub fntrbf( $$$$\&$; ) { my ( $order, $node, $tvtag, $iekv, $fnptr, $res_ref ) = @_; my %trvstak; my @queue; # initialize the queue push @queue, $node; # while there are nodes in the queue while ( ( my $nnode = shift @queue) ) { # If the node has been processed skip it next if $trvstak{$tvtag}{$nnode}; # keep track of the processed nodes $trvstak{$tvtag}{$nnode}=1; # preorder processing - process node before pushing the children to the queue if ( $order =~ /preorder/i) { if ( $fnptr ) { # invoke the function on the nnode if ( not $fnptr->($nnode, $tvtag, $res_ref) ) { warn "Failed executing the function in fntrbf for node \n"; return; } } } # if the nnode has children push them to the queue if ( $nnode and ref($nnode) and ref($nnode) =~ /HASH/i and $nnode->{$tvtag} and ref($nnode->{$tvtag}) =~ /HASH/i and keys %{$nnode->{$tvtag}} ) { # push each child node to the queue for my $ckv ( sort { $iekv->{$a}->{type} cmp $iekv->{$b}->{type} } keys %{$nnode->{$tvtag}} ) { next unless $ckv; warn "Failed to find the $tvtag key_value $ckv in iekv for node \n" and return unless $iekv->{$ckv}; my $cnd = $iekv->{$ckv}; warn "The $tvtag node key_value $ckv is not a hash in iekv for node \n" and return unless ( $cnd and ref($cnd) and ref($cnd) =~ /HASH/i and keys %{$cnd} ); push @queue,$cnd; } } # postorder processing - process node after pushing the children to the queue if ( $order =~ /postorder/i) { if ( $fnptr ) { # invoke the function on the nnode if ( not $fnptr->($nnode, $tvtag, $res_ref ) ) { warn "Failed executing the function in fntrbf for node \n"; return; } } } } return 1; } #--------------------------------------------------------------------------------- # FUNCTION : has_get_cache_dir # # DESC # Get an directory to cache data on the host target # # ARGUMENTS # #--------------------------------------------------------------------------------- sub has_get_cache_dir () { my $cache_dir; return $has::Common::has_metric_config{cache_dir} if $has::Common::has_metric_config{cache_dir}; $cache_dir = $ENV{EMSTATE} if $ENV{EMSTATE}; # if the em state dir doesnt work use temp dir $cache_dir = File::Spec->tmpdir() unless has::Common::hasIsWriteable($cache_dir) and has::Common::hasIsDir($cache_dir); # if temp doest work use current work dir $cache_dir = Cwd::abs_path() unless has::Common::hasIsWriteable($cache_dir) and has::Common::hasIsDir($cache_dir); # terminate if it still doesnt work warn "WARN:Unable to get write access to cache directory $cache_dir\n" and return unless has::Common::hasIsWriteable($cache_dir) and has::Common::hasIsDir($cache_dir); # build the path to the em state directory $cache_dir = catfile($cache_dir,'sysman'); $cache_dir = catfile($cache_dir,'emd'); $cache_dir = catfile($cache_dir,'state'); $cache_dir = catfile($cache_dir,'has'); my $hashostName = has::Common::hasGetLocalHostName(); for my $cdir ( ($hashostName, $has::Common::has_em_targettype, $has::Common::has_em_targetname, $has::Common::has_em_targetguid ) ) { $cdir =~ s/\s+//g; #for portability use only 8 digits $cdir = substr($cdir,0,8); next unless $cdir; $cache_dir = catfile($cache_dir,$cdir); } mkpath($cache_dir,0,0777) unless has::Common::hasIsReadable($cache_dir); warn "WARN:Failed to get a cache dir $cache_dir to cache metric files" and return unless has::Common::hasIsWriteable($cache_dir) and has::Common::hasIsDir($cache_dir); return $cache_dir; } #------------------------------------------------------------------------------ # FUNCTION : hasDoesFileExist # # DESC # true if path exists false otherwise # # ARGUMENTS # path # # RETURNS # #------------------------------------------------------------------------------ sub hasDoesFileExist($;) { my ( $path ) = @_; return unless $path; stat $path; return 1 if -e $path; return; } #------------------------------------------------------------------------------ # FUNCTION : hasIsReadable # # DESC # true if path is readable false otherwise # # ARGUMENTS # path # # RETURNS # #------------------------------------------------------------------------------ sub hasIsReadable($;) { my ( $path ) = @_; return unless $path; stat $path; return 1 if -e $path and -r $path; return; } #------------------------------------------------------------------------------ # FUNCTION : hasIsWriteable # # DESC # true if path is writeable false otherwise # # ARGUMENTS # path # # RETURNS # #------------------------------------------------------------------------------ sub hasIsWriteable($;) { my ( $path ) = @_; return unless $path; stat $path; return 1 if -e $path and -r $path and -w $path; return; } #------------------------------------------------------------------------------ # FUNCTION : hasIsDir # # DESC # true if dir false otherwise # # ARGUMENTS # path # # RETURNS # #------------------------------------------------------------------------------ sub hasIsDir($;) { my ( $path ) = @_; return unless $path; stat $path; return 1 if -e $path and -r $path and -d $path; return; } #------------------------------------------------------------------------------ # FUNCTION : hasReturnFileContents # # DESC # print file contents to stdout # # ARGUMENTS # dir # file name # # RETURNS # return contents dumped to string #------------------------------------------------------------------------------ sub hasReturnFileContents($;$) { my ($dir,$file) = @_; my $pstring; my $flnm; $flnm = catfile($dir,$file) if $dir and $file; $flnm = $dir if $dir and not $flnm; warn "WARN:has::Common::hasReturnFileContent file $flnm does not exist\n" and return unless has::Common::hasDoesFileExist($flnm); warn "WARN:has::Common::hasReturnFileContent file $flnm not readable\n" and return unless has::Common::hasIsReadable($flnm); # Open the file for reading , if it fails dont return an error, # log an error and return gracefully, so metric is blank but with errror open(CSHFH,"$flnm") or warn "WARN:has::Common::hasReturnFileContents Failed to open the cached file $flnm \n" and return; my @cols = <CSHFH>; close(CSHFH) or warn "WARN:has::Common::hasReturnFileContents Failed to close the file $flnm \n"; for my $row ( @cols ) { chomp $row if $row; $row =~ s/^\s+|\s+$//g if $row; $pstring = "$pstring$row\n" and next if $pstring and $row; $pstring = "$row\n" and next if $row; } return $pstring if $pstring; return; } #------------------------------------------------------------------------------ # FUNCTION : hasWriteToFile # # DESC # write contents of array to file # # ARGUMENTS # dir # file name # array with contents # # RETURNS # #------------------------------------------------------------------------------ sub hasWriteToFile($$$;) { my ($dir,$file,$resref) = @_; # open the cache file for the metric and save the results there my $flnm = catfile($dir,$file); open(CSHFH,'>',$flnm) or close(CSHFH) and warn "WARN:has::Common::hasWriteToFile Failed to open the file $flnm \n" and return; # read and save each line to file for my $row ( @{$resref} ) { chomp $row if $row; $row =~ s/^\s+|\s+$//g if $row; print CSHFH "$row\n" if $row; } close(CSHFH) or warn "WARN:has::Common::hasWriteToFile Failed to close the file $flnm \n"; return 1; } #------------------------------------------------------------------------------ # FUNCTION : hasSetCRSEnv # # DESC # Set the cluster environment for the cli/api # # ARGUMENTS # CRS Home if available # # RETURNS # #------------------------------------------------------------------------------ sub hasSetCRSEnv(;$) { my ($crsHome) =@_; my $pathsep = ':'; my $os = has::Common::get_osType(); $pathsep = ';' if $os and $os =~ /^WIN$/; push @has::Common::oldOH,$ENV{ORACLE_HOME} if $ENV{ORACLE_HOME}; push @has::Common::oldCRSHome,$ENV{CRS_HOME} if $ENV{CRS_HOME}; push @has::Common::oldEMCRSHome,$ENV{EM_CRS_HOME} if $ENV{EM_CRS_HOME}; push @has::Common::oldOH,'' unless $ENV{ORACLE_HOME}; push @has::Common::oldCRSHome,'' unless $ENV{CRS_HOME}; push @has::Common::oldEMCRSHome,'' unless $ENV{EM_CRS_HOME}; if ( $crsHome ) { undef $crsHome unless has::Common::hasIsReadable($crsHome); } if ( not $crsHome ) { $crsHome = has::Common::hasGetCRSHome(); } if ( not $crsHome ) { $crsHome = has::Common::hasGetEnvCRSHome(); } $ENV{CRS_HOME} = $crsHome if $crsHome; $ENV{ORACLE_HOME} = $crsHome if $crsHome; $ENV{PATH} = '' unless $ENV{PATH}; my %pathOrder = (1=>'EMDROOT', 2=>'CRS_HOME'); for my $order ( sort {$a <=> $b} keys %pathOrder ) { my $path = $pathOrder{$order}; next unless $ENV{$path}; my $binPath = catfile($ENV{$path},'bin'); $ENV{PATH} = "$binPath$pathsep$ENV{PATH}" if $binPath; } # this is temporary to take care of emcrsp in has/bin not linked to oracle/bin if ( $ENV{CRS_HOME} and $ENV{ADE_VIEW_ROOT} and $ENV{NDE_PRODUCT} and not defined $ENV{HAS_TEST_MODE} ) { my $hasbinpath = catfile($ENV{CRS_HOME},'..'); $hasbinpath = catfile($hasbinpath,'bin'); $ENV{PATH} = "$hasbinpath$pathsep$ENV{PATH}"; } return 1; } #------------------------------------------------------------------------------ # FUNCTION : hasRestoreCRSEnv # # DESC # restore back the env # # ARGUMENTS # # RETURNS # #------------------------------------------------------------------------------ sub hasRestoreCRSEnv() { my $oldOracleHome; my $oldCHome; my $oldEMCHome; $oldOracleHome = pop @has::Common::oldOH if @has::Common::oldOH; if ( $oldOracleHome ) { $ENV{ORACLE_HOME} = $oldOracleHome; } else { delete $ENV{ORACLE_HOME} if $ENV{ORACLE_HOME}; } $oldCHome = pop @has::Common::oldCRSHome if @has::Common::oldCRSHome; if ( $oldCHome ) { $ENV{CRS_HOME} = $oldCHome; } else { delete $ENV{CRS_HOME} if keys %ENV and $ENV{CRS_HOME}; } $oldEMCHome = pop @has::Common::oldEMCRSHome if @has::Common::oldEMCRSHome; if ( $oldEMCHome ) { $ENV{EM_CRS_HOME} = $oldEMCHome; } else { delete $ENV{EM_CRS_HOME} if $ENV{EM_CRS_HOME}; } return 1; } #------------------------------------------------------------------------------ # FUNCTION : hasGetEnv # # DESC # restore back the env before regression tests # this will make sure env is stored when capturign for regression # and is used durig regression # # ARGUMENTS # # RETURNS # the ref to has of env variables # #------------------------------------------------------------------------------ sub hasGetEnv() { my %env; for my $k ( keys %ENV ) { $env{$k} = $ENV{$k}; } return \%env; } #------------------------------------------------------------------------------ # FUNCTION : hasGetNodeCRSHome # # DESC # return the CRSHome for the node # # ARGUMENTS # nodename # crsHome if known # # RETURN # CRSHome # #------------------------------------------------------------------------------ sub hasGetNodeCRSHome(;$$) { # do not call clusterconfig or clusternodes here as those functions call this sub # just look up the different data structures to pick the right value my ( $nodename,$crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); $nodename =~ s/\s+//g if $nodename; if ( $nodename ) { undef $nodename if $nodename =~ /^$/ or $nodename eq ''; } $confref = has::Common::hasGetClusterConfig($crsHome); # get crs home for each node, assuming they are same on all nodes as we have no way # to get crsHome from other nodes unless css api provides it if ( $nodename and $confref and ref($confref) and keys %{$confref} ) { my $ndCrsHome; for my $ch ( keys %{$confref} ) { next unless $confref->{$ch} and $confref->{$ch}{node} and $confref->{$ch}{node}{details} and $confref->{$ch}{node}{details}{$nodename} and $confref->{$ch}{node}{details}{$nodename}{crs_home}; $ndCrsHome = $ch; } return $ndCrsHome if $ndCrsHome; } return has::Common::hasGetCRSHome($crsHome); } #------------------------------------------------------------------------------ # FUNCTION : hasGetCRSHome # # DESC # return the CRSHome for the local node # # ARGUMENTS # crsHome if known # # RETURN # CRSHome # #------------------------------------------------------------------------------ sub hasGetCRSHome(;$) { # do not call clusterconfig or clusternodes here as those functions call this sub # just look up the different data structures to pick the right value my ( $crsHome ) = @_; my $disCRSHome; # get the discovery home my $confref = has::Common::hasDiscoverCluster(); # is a crsHome is passed and it matched the discovered crsHome viola, that is the crsHome # the order of search directories for olsnode/lsnodes my %olsnodeorder; if ( $crsHome ) { $olsnodeorder{0}{path}=$crsHome; } $olsnodeorder{10}{path}='CRS_HOME'; $olsnodeorder{11}{path}='EM_CRS_HOME'; $olsnodeorder{12}{path}='ORACLE_HOME'; # counter for discovered firs in olsnodeorder my $i = 1; # pick the crsHome which matches the env variables # sort in desc IDX order as newer crs homes have higher IDX number in installs where theure might have been a upgrade my %crshomeidx; for my $ch ( keys %{$confref} ) { if ( $confref->{$ch} and $confref->{$ch}{discover} and $confref->{$ch}{discover}{IDX} ) { $crshomeidx{$ch} = $confref->{$ch}{discover}{IDX} and next ; } $crshomeidx{$ch} = -1; } for my $ch ( sort { $crshomeidx{$b} <=> $crshomeidx{$a} } keys %crshomeidx ) { $disCRSHome = $ch; #if this is not discovered then skip next unless $confref->{$ch}{discover}; for my $order ( sort {$a <=> $b} keys %olsnodeorder ) { my $path; next unless $olsnodeorder{$order} and $olsnodeorder{$order}{path}; if ( $olsnodeorder{$order}{path} =~ /^(CRS_HOME|EM_CRS_HOME|ORACLE_HOME|EMDROOT)$/ ) { $path = $ENV{$olsnodeorder{$order}{path}} if $ENV{$olsnodeorder{$order}{path}}; } else { $path = $olsnodeorder{$order}{path}; } next unless $path; next if $path =~ /^(#CRS_HOME#|CRS_HOME|EM_CRS_HOME|ORACLE_HOME|EMDROOT)$/; # discovered crsHome from inventory is different from crsHome if ( $disCRSHome eq $path ) { return $disCRSHome; } else { if ( $olsnodeorder{$order}{path} =~ /^(CRS_HOME|EM_CRS_HOME|ORACLE_HOME|EMDROOT)$/ ) { warn "DEBUG:has::Common::hasGetCRSHome:Discovered cluster home $disCRSHome is different from $olsnodeorder{$order}{path} $path"; } else { warn "DEBUG:has::Common::hasGetCRSHome:Discovered cluster home $disCRSHome is different from $path"; } } } # no env matches the disc home, return passed crs home, discovered home or env as crs home # in that order $olsnodeorder{$i}{path}= $disCRSHome if $disCRSHome; $i++; } # the discoovered dir does nto match any of the other dirs for my $order ( sort {$a <=> $b} keys %olsnodeorder ) { my $path; next unless $olsnodeorder{$order} and $olsnodeorder{$order}{path}; if ( $olsnodeorder{$order}{path} =~ /^(CRS_HOME|EM_CRS_HOME|ORACLE_HOME|EMDROOT)$/ ) { $path = $ENV{$olsnodeorder{$order}{path}} if $ENV{$olsnodeorder{$order}{path}}; } else { $path = $olsnodeorder{$order}{path}; } next unless $path; next if $path =~ /^(#CRS_HOME#|CRS_HOME|EM_CRS_HOME|ORACLE_HOME|EMDROOT)$/; next unless has::Common::hasIsReadable($path); warn "DEBUG:has::Common::hasGetCRSHome: Using $path as cluster home" and return $path; } # no disc home and no env for crs home warn "WARN:has::Common::hasGetCRSHome Failed to get cluster home dir for " and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetEnvCRSHome # # DESC # return the CRSHome from the env # # ARGUMENTS # # RETURN # CRSHome # #------------------------------------------------------------------------------ sub hasGetEnvCRSHome() { my %olsnodeorder; $olsnodeorder{1}{path}='CRS_HOME'; $olsnodeorder{2}{path}='EM_CRS_HOME'; $olsnodeorder{3}{path}='ORACLE_HOME'; for my $order ( sort {$a <=> $b} keys %olsnodeorder ) { my $path; next unless $olsnodeorder{$order} and $olsnodeorder{$order}{path}; if ( $olsnodeorder{$order}{path} =~ /CRS_HOME|EM_CRS_HOME|ORACLE_HOME|EMDROOT/ ) { $path = $ENV{$olsnodeorder{$order}{path}} if $ENV{$olsnodeorder{$order}{path}}; } else { $path = $olsnodeorder{$order}{path}; } next unless $path; next if $path =~ /#CRS_HOME#/; next unless has::Common::hasIsReadable($path); return $path; } # no disc home and no env for crs home warn "WARN:has::Common::hasGetEnvCRSHome Failed to get cluster home from env " and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetLocalHostName # # DESC # return the Host Name # # ARGUMENTS # #------------------------------------------------------------------------------ sub hasGetOSLocalHostName() { # return host name is not cluster my $hostName; #this module is not available in emagent 10.2.0.4 #my $subOSDHost = "hostOSD::getHostName"; #my $subref = \&$subOSDHost; if ( $hostNameSub ) { my $fnref = \&$hostNameSub; $hostName = &$fnref; } $hostName = hostname unless $hostName; return $hostName; } sub hasGetLocalHostName() { my $confref = has::Common::getClusterCacheRef(); if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{pre11gr2_config}{host_name} if $confref->{$ch}{pre11gr2_config} and $confref->{$ch}{pre11gr2_config}{host_name}; return $confref->{$ch}{host_name} if $confref->{$ch}{host_name}; } } # return host name is not cluster my $hostName = has::Common::hasGetOSLocalHostName(); if ( $hostName and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { $confref->{$ch}{pre11gr2_config}{host_name} = $hostName; $confref->{$ch}{host_name} = $hostName; } } return $hostName if $hostName; warn "ERROR:has::Common::hasGetLocalHostName:Failed to get the host name for the cluster node" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetDomainName # # DESC # return the Host Domain # # ARGUMENTS # host name # #------------------------------------------------------------------------------ sub hasGetDomainName(;$) { # return host Domain my ( $hostName ) = @_; my $domain; $hostName = hostname unless $hostName; $hostName = hasGetLocalHostName() unless $hostName; if ( $hostDomainSub ) { my $fnref = \&$hostDomainSub; $domain = &$fnref($hostName); } return $domain; warn "ERROR:has::Common::hasGetDomainName:Failed to get the Domain name for the node" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasCheckForEmcrsp # # DESC # checks if emcrsp is present # # ARGUMENTS # crsHome if known # # RETRUNS # 1 for true #------------------------------------------------------------------------------ sub hasCheckForEmcrsp($) { my ( $crsHome ) = @_; # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { # get the cluster home by discovery $crsHome = has::Common::hasGetCRSHome(); if ( not $crsHome ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } warn "DEBUG:has::Common::hasCheckForEmcrsp: cluster home directory passed is null" and return unless $crsHome; # check if emcrsp exists in the crs bin dir my $emcrsppath; my %dirlist; # this is only in dev env my $hasbin = catdir('has','bin'); %dirlist = ( 1=>$crsHome ); for my $order ( sort {$a<=>$b} keys %dirlist ) { my $dir = $dirlist{$order}; next unless $dir; for my $bin ( ( 'bin',$hasbin ) ) { my $binpath = catdir($dir,$bin); for my $exe ( ('emcrsp','emcrsp.exe','emcrsp.bat') ) { $emcrsppath = catfile($binpath,$exe); if ( has::Common::hasIsReadable($emcrsppath) ) { last; } else { undef $emcrsppath; } } last if $emcrsppath; } last if $emcrsppath; } # use emcrsp to get node name if it exists warn "DEBUG:has::Common::hasCheckForEmcrsp emcrsp is not present in cluster home $crsHome" and return unless $emcrsppath; return 1; } #------------------------------------------------------------------------------ # FUNCTION : hasDiscoverCluster # # DESC # return a hash of # {coma_seperated => # nodearray => ) # of nodes in a cluster # # ARGUMENTS # # RETURNS # hash result list #------------------------------------------------------------------------------ sub hasDiscoverCluster(;$) { #<HOME NAME="OraCrs11g_home" LOC="/scratch/11.1.0.6/crs" TYPE="O" IDX="1" CRS="true"> # <NODE_LIST> # <NODE NAME="stbdq16"/> # <NODE NAME="stbdq17"/> # </NODE_LIST> #</HOME> sub has_inventory_fn(\%\%) { my ( $elref, $rsref ) = @_; return 1 unless $elref->{element} and $elref->{element} =~ /^(HOME)$/i; return 1 unless $elref->{attrs} and $elref->{attrs}{CRS} and $elref->{attrs}{CRS} =~ /^true$/i; return 1 if $elref->{attrs} and $elref->{attrs}{remote} and $elref->{attrs}{remote} =~ /^true$/i; return 1 if $elref->{attrs} and $elref->{attrs}{REMOTE} and $elref->{attrs}{REMOTE} =~ /^true$/i; warn "WARN:has::Common::hasDiscoverCluster LOC is NULL for CRS in Oracle Inventory file" and return 1 unless $elref->{attrs} and $elref->{attrs}{LOC}; # save oracle homes, add nodes later on my $ch = $elref->{attrs}{LOC}; $rsref->{$ch}{discover}{crs_home}=$ch; my $idx = $elref->{attrs}{IDX} if exists $elref->{attrs}{IDX}; $idx = 0 unless defined $idx; $idx++ if $idx =~ /\d+/; $rsref->{$ch}{discover}{IDX}=$idx; $rsref->{$ch}{discover}{IDX}=-1 unless $rsref->{$ch}{discover}{IDX}; $rsref->{$ch}{discover}{TYPE}=$elref->{attrs}{TYPE} if $elref->{attrs}{TYPE}; $rsref->{$ch}{discover}{TYPE}=0 unless $rsref->{$ch}{discover}{TYPE}; # get NODE NAME from children return 1 unless $elref->{children} and @{$elref->{children}}; for my $nodeListRef ( @{$elref->{children}} ) { next unless $nodeListRef and $nodeListRef->{element} and $nodeListRef->{element} =~ /^NODE_LIST$/i; next unless $nodeListRef->{children} and @{$nodeListRef->{children}}; for my $noderef ( @{$nodeListRef->{children}} ) { next unless $noderef and $noderef->{element} and $noderef->{element} =~ /^NODE$/i; warn "WARN:has::Common::hasDiscoverCluster NODE name is null in Oracle Inventory file" and next unless $noderef->{attrs} and $noderef->{attrs}{NAME}; $rsref->{$ch}{discover}{nodes}{$noderef->{attrs}{NAME}}=1; } last; } return 1; } my ( $dynProp ) = @_; my $invPath; my $invXMLContent; my %xmlVar; my $confref = has::Common::getClusterCacheRef(); # if already discovered returned the cached values if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref if $confref->{$ch}{discover}; } } #bugfix 7692044 my $os = has::Common::get_osType(); my $scriptsDir = $ENV{EM_SCRIPTS_DIR} if $ENV{EM_SCRIPTS_DIR}; my $perlBin = $ENV{EM_PERLBIN_DIR} if $ENV{EM_PERLBIN_DIR}; if ( $os and $os =~ /^WIN$/ ) { #bugfix 8988446 my $perlexe; if ( $perlBin ) { $perlexe = catfile($perlBin,'perl'); } if ( $scriptsDir ) { $scriptsDir = catfile($scriptsDir,'has'); } if ( not $scriptsDir ) { $scriptsDir = $FindBin::Bin if $FindBin::Bin; } if ( not $perlexe ) { $perlexe = $Config{perlpath} if $Config{perlpath}; } if ( $scriptsDir and $perlexe ) { my $has_metrics_script = catfile($scriptsDir,'has_getinvdir.pl'); $invPath = `$perlexe $has_metrics_script`; chomp $invPath if $invPath; } } else { $invPath= has::Common::getInventoryXmlPath(); } warn "WARN:has::Common:hasDiscoverCluster Failed to find Oracle Inventory File " and return unless $invPath; warn "WARN:has::Common:hasDiscoverCluster Failed to read Oracle Inventory File $invPath" and return unless has::Common::hasIsReadable($invPath); $invXMLContent = has::Common::hasReturnFileContents($invPath); warn "WARN:has::Common:hasDiscoverCluster Oracle Inventory file $invPath has no content\n" and return unless $invXMLContent; %xmlVar = has::Common::parse_xml($invXMLContent); has::Common::traverse_xml(\%xmlVar,\&has::Common::has_handle_error,\&has_inventory_fn,$confref) or warn "WARN:Failed to traverse the Oracle Inventory xml $invXMLContent" and return; # if this is for dynamic prop, we need only the crshome not the other stuff return $confref if $dynProp; #get clustername for each cluster #all nodes with the same clusterHome are bunched under the same crsHome my @nodearray; my $nodelist; my $clsName; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { warn "DEBUG:has::Common:hasDiscoverCluster cluster home $ch is not in Inventory file $invXMLContent" unless $confref->{$ch}{discover} and keys %{$confref->{$ch}{discover}}; # since this is a cluster home from discovery use cemutls to get cluster name $clsName = has::Common::hasCemutloClusterName($ch); $confref->{$ch}{discover}{cluster_name}=$clsName if $clsName; $confref->{$ch}{discover}{crs_home}=$ch; # build the node list for this crsHome if ( $confref->{$ch}{discover}{nodes} ) { for my $node ( keys %{$confref->{$ch}{discover}{nodes}} ) { next unless $node; push @nodearray,$node; $nodelist = "$nodelist,$node" if $nodelist; $nodelist = $node unless $nodelist; } } # copy the cluster name,home ,nodelist, nodearray dir back to the root hash $confref->{$ch}{discover}{nodelist} = $nodelist if $nodelist; $confref->{$ch}{discover}{nodearray} = \@nodearray if @nodearray; } } if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { has::Common::clusterConfigCopyVals($confref->{$ch}{discover}, $confref->{$ch}) if $confref->{$ch}{discover}; } } return $confref; } #------------------------------------------------------------------------------ # FUNCTION : hasGetEntityInformation # # DESC # return the required entity information for the cluster # # ARGUMENTS # ref to the metadata to be used to extract data # crsHome if known # fn pointer or null if you want to use the default fn # # meta should have # ->{cmd} # ->{element_name} # ->{attrs}{[attr_name]} # ->{name_value}{[name]} # RETURN # ref to the hash to be filled in with values #------------------------------------------------------------------------------ sub hasGetEntityInformation($;$$) { # name : hasGetEntityInformation_fn # desc : it filters our the required information # # arg : # ref to xml element to be filtered # ref to the result hass entities array # ref to the metadata hash to be used to extract data # sub hasGetEntityInformation_fn($$$) { my ( $elref, $rsref, $mtref ) = @_; # return unless meta data is provided return 1 unless $mtref and $mtref->{element_name}; return 1 unless $elref->{element} and $elref->{element} =~ /^$mtref->{element_name}$/i; # get the name for this entity my $thisval; if ( $elref->{attrs} ) { for my $hdval ( keys %{$elref->{attrs}} ) { $thisval = $elref->{attrs}{$hdval} if $hdval =~ /^entity_name$/; } } $thisval =~ s/^\s+|\s+$//g; warn "WARN:has::Common:: failed to get entity_name from $elref->{element}" and return 1 unless $thisval; # if there are attrs to be read read them if ( $mtref->{$mtref->{element_name}}{attrs} ) { for my $hdval ( keys %{$elref->{attrs}} ) { $hdval =~ s/^\s+|\s+$//g; next unless $hdval; next unless $mtref->{$mtref->{element_name}}{attrs}{$hdval}; $rsref->{$thisval}{$hdval} = $elref->{attrs}{$hdval} if $elref->{attrs}{$hdval}; $rsref->{$thisval}{$hdval} =~ s/^\s+|\s+$//g if $rsref->{$thisval}{$hdval}; } } # return unless there are name value paris to be read from attributes return 1 unless $mtref->{$mtref->{element_name}}{name_value}; # read all name=value pairs from the attributes of the node for my $elref1 ( @{$elref->{children}} ) { next unless $elref1->{element} =~ /^attributes$/; for my $elref2 ( @{$elref1->{children}} ) { next unless $elref2->{element} =~ /^attribute$/; my $name; my $value; for my $elref3 ( @{$elref2->{children}} ) { next unless $elref3->{element} =~ /^(name|value)$/; $name = $elref3->{name} if $elref3->{element} =~ /^name$/; $value = $elref3->{name} if $elref3->{element} =~ /^value$/; $name =~ s/^\s+|\s+$//g if $name; $value =~ s/^\s+|\s+$//g if $value; } next unless $name; # if this name is not required skip it next unless $mtref->{$mtref->{element_name}}{name_value}{$name}; $value = '' unless $value; $rsref->{$thisval}{$name}=$value; } } return 1; } my ( $metaref,$crsHome,$fn_ptr ) = @_; $fn_ptr = \&hasGetEntityInformation_fn unless $fn_ptr; my $reslistref; return 1 unless $metaref and $metaref->{cmd}; # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { $crsHome = has::Common::hasGetCRSHome(); # get the cluster home by discovery if ( not $crsHome or not has::Common::hasCheckForEmcrsp($crsHome) ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } return $reslistref and warn "WARN:has::Common::hasGetEntityInformation:Cluster home is not passed or not set in env" unless $crsHome; return $reslistref and warn "DEBUG:has::Common::hasGetEntityInformation:binary emcrsp is not present in $crsHome" unless has::Common::hasCheckForEmcrsp($crsHome); has::Common::hasSetCRSEnv($crsHome); my $cmdresults = has::Common::runsystemcommand($metaref->{cmd}); has::Common::hasRestoreCRSEnv(); warn "WARN:has::Common::hasGetEntityInformation Failed to get results from command - $metaref->{cmd}" and return $reslistref unless $cmdresults; my %xmlvar = has::Common::parse_xml($cmdresults); my %resulthash; has::Common::traverse_xml(\%xmlvar,\&has::Common::has_handle_error,$fn_ptr,\%resulthash,$metaref); return \%resulthash; } #------------------------------------------------------------------------------ # FUNCTION : hasCemutlsClusterName # # DESC # get the clustername from cemutls for non oracle clusters # # ARGUMENTS # crsHome for vendor or EMDROOR # RETURN # cluster name #------------------------------------------------------------------------------ sub hasCemutlsClusterName($) { my ($dir) = @_; # bug 4667678 # TBD is solaris 64 bit run the 64 bit cemutls my $cemutls; my %cemutls_command_args = (exit_failure_list => [()]); if (has::Common::get_osType() eq "SOL") { # bug fix 8459125 my $o = has::Common::runsystemcommand("file /opt/ORCLcluster/lib/libskgxn2.so 2>&1",'',\%cemutls_command_args); if ($o and $o =~ /64-bit/) { my $cemutls64path; $cemutls64path = catfile($dir,'bin') if $dir; $cemutls64path = catfile($cemutls64path,'cemutls64') if $cemutls64path; stat $cemutls64path if $cemutls64path; $cemutls = "cemutls64" if $cemutls64path and -e $cemutls64path; } } $cemutls = "cemutls" unless $cemutls; %cemutls_command_args = (exit_failure_list => [()]); has::Common::hasSetCRSEnv($dir); my $vo = has::Common::runsystemcommand("$cemutls -w 2>&1",'',\%cemutls_command_args); has::Common::hasRestoreCRSEnv(); warn "DEBUG:has::Common::hasCemutlsClusterName Error getting cluster name from $cemutls" and return if $cemutls_command_args{command_return_status}; chomp($vo) if $vo; $vo =~ s/\n/ /g if $vo; $vo =~ s/^\s+|\s+$// if $vo; return $vo if $vo; warn "DEBUG:has::Common::hasCemutlsClusterName Failed to get cluster name from $cemutls" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasCemutloClusterName # # DESC # get the clustername from cemutlo for oracle clusters # # ARGUMENTS # crsHome # RETURN # cluster name #------------------------------------------------------------------------------ sub hasCemutloClusterName($) { my ( $crsHome) = @_; my %cemutlo_command_args = (exit_failure_list => [()]); my $clusterName; has::Common::hasSetCRSEnv($crsHome); $clusterName = has::Common::runsystemcommand('cemutlo -n 2>&1','',\%cemutlo_command_args); has::Common::hasRestoreCRSEnv(); warn "DEBUG:has::Common::hasCemutloClusterName Error getting cluster name from cemutlo" and return if $cemutlo_command_args{command_return_status}; chomp($clusterName) if $clusterName; $clusterName =~ s/\n/ /g if $clusterName; $clusterName =~ s/^\s+|\s+$// if $clusterName; return $clusterName if $clusterName; warn "DEBUG:has::Common::hasCemutloClusterName Failed to get cluster name from cemutlo" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasSearchClusterName # # DESC # get the clustername for the cluster directory passed # if not look up inventory and get the cluster name from the # cluster installs therte # if not use EMDROOT to get clustername using cemutls # # ARGUMENTS # crsHome for vendor or EMDROOR # RETURN # cluster name # list of clustername, clusterhome,isVendor used to get the cluster name # isVendor is 0 for oracle ( cemutlo ) # 1 for vendor ( cemutls ) #------------------------------------------------------------------------------ sub hasSearchClusterName(;$) { my ( $crsHome ) = @_; my $clsName; my $clsdiscref; if ( $crsHome ) { $clsName = has::Common::hasCemutloClusterName($crsHome); } if ( $clsName) { return wantarray? ($clsName,$crsHome,0):$clsName; } $clsdiscref = has::Common::hasDiscoverCluster(); if ( $clsdiscref and keys %{$clsdiscref} ) { for my $ch ( keys %{$clsdiscref} ) { if ( $clsdiscref->{$ch}{cluster_name} ) { $clsName = $clsdiscref->{$ch}{cluster_name}; $crsHome = $ch; last; } } } if ( $clsName) { return wantarray? ($clsName,$crsHome,0):$clsName; } if ( $ENV{EMDROOT} ) { $clsName = has::Common::hasCemutlsClusterName($ENV{EMDROOT}); undef $crsHome; } elsif ( $crsHome ) { $clsName = has::Common::hasCemutlsClusterName($crsHome); } else { warn "WARN:has::Common::hasSearchClusterName: EMDROOT is not passed to get the cluster name" } if ($clsName) { return wantarray? ($clsName,$crsHome,1):$clsName; } warn "WARN:has::Common::hasSearchClusterName:Failed to get clustername \n" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasIsVendorClusterware # # DESC # get the clustername from cemutls for non oracle clusters # # ARGUMENTS # crsHome for vendor or EMDROOR # RETURN # cluster name #------------------------------------------------------------------------------ sub hasIsVendorClusterware($) { my ( $dir) = @_; # bug 4667678 # TBD is solaris 64 bit run the 64 bit cemutls my $cemutls; if (has::Common::get_osType() eq "SOL") { my $o = has::Common::runsystemcommand(`file /opt/ORCLcluster/lib/libskgxn2.so 2>&1`,'',); if ($o =~ /64-bit/) { $cemutls = "cemutls64"; } else { $cemutls = "cemutls"; } } else { $cemutls = "cemutls"; } my %cemutls_command_args = (exit_failure_list => [()]); has::Common::hasSetCRSEnv($dir); my $vo = has::Common::runsystemcommand("$cemutls -w 2>&1",'',\%cemutls_command_args); has::Common::hasRestoreCRSEnv(); chomp($vo) if $vo; $vo =~ s/\n/ /g if $vo; $vo =~ s/^\s+|\s+$// if $vo; # if cemutls fails then this is not a vendor cluster if ( $cemutls_command_args{command_return_status} ) { return wantarray?($vo,$cemutls_command_args{command_return_status}):0; } # cemutls is successful do this is a vendor cluster return wantarray?($vo,$cemutls_command_args{command_return_status}) :1; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterConfigPre11g # # DESC # return the config information for the cluster emcrsp # # ARGUMENTS # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # RETURN # ref to the hash to be filled in with values #------------------------------------------------------------------------------ sub hasGetClusterConfigPre11g(;$$) { my ( $crsHome,$dynProp ) = @_; undef $crsHome if $crsHome and not has::Common::hasIsReadable($crsHome); # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { # get the cluster home by discovery $crsHome = has::Common::hasGetCRSHome(); if ( not $crsHome ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } warn "WARN:has::Common::hasGetClusterConfigPre11g:Cluster home is not passed or not set in env" unless $crsHome; my $isVendorCW = 1; my $version; my $patch; my $errMsg; my $vendor; my $clsName; my $o; my $vo; my $CRSVersion; my $cmd_status; #There is a CRS home in this cluster my $nCrsHome; # I added this check as this will result in timeout of dynamic property comps # if crs home is known then do nothins # we should add a flag to indicate if this is called from dynamic prop or a metric # TBD if ( $dynProp ) { ($clsName,$nCrsHome,$isVendorCW) = has::Common::hasSearchClusterName($crsHome); if ( $nCrsHome and $crsHome and $crsHome ne $nCrsHome ) { warn "WARN:has::Common::hasGetClusterConfigPre11g the cluster home $nCrsHome is different from $crsHome"; $crsHome=$nCrsHome; } elsif ( $nCrsHome and not $crsHome ) { warn "WARN:has::Common::hasGetClusterConfigPre11g the cluster home is $nCrsHome "; $crsHome=$nCrsHome; } elsif ( $clsName and not $nCrsHome ) { warn "WARN:has::Common::hasGetClusterConfigPre11g: No home found for cluster $clsName ,different from $crsHome"; } } if ( $crsHome and $crsHome !~ /#CRS_HOME#/ ) { ( $vo,$cmd_status) = has::Common::hasIsVendorClusterware($crsHome); # No vendor clusterware in use if cemutls fails if ( $cmd_status ) { $isVendorCW = 0; } else { $isVendorCW = 1; } # use cemutlo to get info on oracle clusterware my %command_args = (exit_failure_list => [()]); has::Common::hasSetCRSEnv($crsHome); $o = has::Common::runsystemcommand('cemutlo -w 2>&1','',\%command_args); has::Common::hasRestoreCRSEnv(); if ( $command_args{command_return_status} ) { warn("ERROR:has:Common::hasGetClusterConfigPre11g:Failed executing command cemutlo -w"); } else { chomp($o) if $o; $o =~ s/\n/ /g if $o; $o =~ s/^\s+|\s+$// if $o; warn("ERROR:has:Common::hasGetClusterConfigPre11g:Failed to get any results from cemutlo -w") unless $o; warn("ERROR:has:Common::hasGetClusterConfigPre11g:Unknown format of the output from cemutlo -w : $o") if $o and $o !~ /(.*)\:(.*)\:(.*)/; # use the output from cemutls if output from cemutlo does not match $o = $vo if $vo and not $o and $o !~ /(.*)\:(.*)\:(.*)/; ($version,$patch,$vendor) = ($o =~ /(.*)\:(.*)\:(.*)/) if $o and $o =~ /(.*)\:(.*)\:(.*)/; $version = "$version.$patch" if $version and $patch; } #Active CRS Version %command_args = (exit_failure_list => [()]); has::Common::hasSetCRSEnv($crsHome); $o = has::Common::runsystemcommand('crsctl query crs activeversion 2>&1','',\%command_args); has::Common::hasRestoreCRSEnv(); warn("ERROR:has:Common::hasGetClusterConfigPre11g:Failed executing command crsctl query crs activeversion") if $command_args{command_return_status}; chomp($o) if $o; $o =~ s/\n/ /g if $o; $o =~ s/^\s+|\s+$// if $o; warn("ERROR:has:Common::hasGetClusterConfigPre11g:Failed to get any results from crsctl query crs activeversion") unless $o; if ( $command_args{command_return_status} ) { $CRSVersion = ''; } elsif ( $o ) { warn("ERROR:has:Common::hasGetClusterConfigPre11g:Unknown format of the output from crsctl query crs activeversion : $o") if $o and $o !~ /\[([\d|\.]+)\]/; ($CRSVersion) = ( $o =~ /\[([\d|\.]+)\]/ ) if $o and $o =~ /\[([\d|\.]+)\]/; } # 10.1 crsctl doesn't return the version. $CRSVersion = '10.1' if not $CRSVersion and $version and $version =~ /^1.1$/; } else { #No CRS is known to the cluster $crsHome = $ENV{EMDROOT} if $ENV{EMDROOT}; ($o,$cmd_status) = has::Common::hasIsVendorClusterware($crsHome); # cemutls -w failed, so this is a oracle cluster if ( $cmd_status ) { warn("WARN:has:Common::hasGetClusterConfigPre11g:Failed executing command cemutls -w as oracle cluster"); } elsif ( $o ) { warn("ERROR:has:Common::hasGetClusterConfigPre11g: Unknown format of the output from cemutls -w : $o") unless $o =~ /(.*)\:(.*)\:(.*)/; ($version,$patch,$vendor) = ($o =~ /(.*)\:(.*)\:(.*)/) if $o =~ /(.*)\:(.*)\:(.*)/; } else { warn("ERROR:has:Common::hasGetClusterConfigPre11g: Vendor cluster, but failed to get results from cemutls -w : "); } $version = "$version.$patch" if $version and $patch; } $crsHome = '#CRS_HOME#' unless $crsHome; my $confref = has::Common::getClusterCacheRef(); $confref->{$crsHome}{pre11gr2_config}{cluster_name}= $clsName if $clsName; $confref->{$crsHome}{pre11gr2_config}{crs_version} = $CRSVersion if $CRSVersion; $confref->{$crsHome}{pre11gr2_config}{vendor} = $vendor if defined $vendor; $confref->{$crsHome}{pre11gr2_config}{version} = $version if defined $version; $confref->{$crsHome}{pre11gr2_config}{isvendorcw} = $isVendorCW if defined $isVendorCW; has::Common::clusterConfigCopyVals($confref->{$crsHome}{pre11gr2_config}, $confref->{$crsHome}) if $crsHome and $confref->{$crsHome}{pre11gr2_config}; return $confref; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterGetNodeNamePre11g # # DESC # return the node name for the local node using olsnode/lsodes # # ARGUMENTS # crsHome if known # # RETURN # ref to hash # #------------------------------------------------------------------------------ sub hasGetClusterGetNodeNamePre11g(;$) { my ( $crsHome ) = @_; my $nodename; $crsHome =~ s/^\s+|\s+$//g if $crsHome; # the order of search directories for olsnode/lsnodes my %olsnodeorder; my $ncrsHome; if ( $crsHome ) { $olsnodeorder{0}{path}=$crsHome; $olsnodeorder{0}{cmd}='olsnodes'; } my $discCrsHome = has::Common::hasGetCRSHome(); if ( $discCrsHome ) { $olsnodeorder{1}{path}=$discCrsHome; $olsnodeorder{1}{cmd}='olsnodes'; } $olsnodeorder{2}{path}='CRS_HOME'; $olsnodeorder{2}{cmd}='olsnodes'; $olsnodeorder{3}{path}='EM_CRS_HOME'; $olsnodeorder{3}{cmd}='olsnodes'; $olsnodeorder{4}{path}='ORACLE_HOME'; $olsnodeorder{4}{cmd}='olsnodes'; $olsnodeorder{5}{path}='EMDROOT'; $olsnodeorder{5}{cmd}='lsnodes'; for my $order ( sort {$a <=> $b} keys %olsnodeorder ) { my $path; my $cmd; next unless $olsnodeorder{$order} and $olsnodeorder{$order}{path} and $olsnodeorder{$order}{cmd}; $path = $olsnodeorder{$order}{path}; $path = $ENV{$olsnodeorder{$order}{path}} if $ENV{$olsnodeorder{$order}{path}}; next unless $path; next if $path =~ /#CRS_HOME#|EMDROOT|CRS_HOME|EM_CRS_HOME|ORACLE_HOME/; next unless has::Common::hasIsReadable($path); $cmd = $olsnodeorder{$order}{cmd}; #get the list of nodes using olsnodes my %command_args = (exit_failure_list => [()]); my $fullcmd; for my $ext ( ( 'exe', 'bat' , undef) ) { my $ecmd; $ecmd = "$cmd\.$ext" if $ext; $ecmd = $cmd unless $ecmd; $fullcmd = catfile($path,'bin',$ecmd); stat $fullcmd; last if has::Common::hasIsReadable($fullcmd); undef $fullcmd; } next unless $fullcmd; # bug 4667678 has::Common::hasSetCRSEnv($path); #Bug fix#9117595 $nodename = has::Common::runsystemcommand($fullcmd.' -l 2>&1','',\%command_args); has::Common::hasRestoreCRSEnv(); warn("DEBUG:has::Common::hasGetClusterGetNodeNamePre11g:Failed executing command **$fullcmd") and next if $command_args{command_return_status}; # remove new line chomp $nodename if $nodename; if ( $nodename ) { $ncrsHome = $path unless $path =~ /EMDROOT/; warn("DEBUG:has::Common::hasGetClusterGetNodeNamePre11g:CRS home is: $ncrsHome") and last if $ncrsHome; warn("DEBUG:has::Common::hasGetClusterGetNodeNamePre11g:No CRS home is: using $fullcmd to get node name, possibly vendor clusterware") and last unless $ncrsHome; } } my $confref = has::Common::getClusterCacheRef(); warn("WARN:has::Common::hasGetClusterGetNodeNamePre11g:Failed to get nodename from cluster binaries olsnodes/lsnodes") unless $nodename; return $confref unless $nodename; $crsHome = $ncrsHome if $ncrsHome and not $crsHome; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { $confref->{$ch}{pre11gr2_config}{nodename} = $nodename unless $confref->{$ch}{pre11gr2_config}{nodename}; } if ( $crsHome ) { $confref->{$crsHome}{pre11gr2_config}{nodename} = $nodename if $nodename; $confref->{$crsHome}{pre11gr2_config}{crs_home} = $crsHome unless $confref->{$crsHome}{pre11gr2_config}{crs_home}; } } else { $crsHome = '#CRS_HOME#' unless $crsHome; $confref->{$crsHome}{pre11gr2_config}{nodename} = $nodename; $confref->{$crsHome}{pre11gr2_config}{crs_home} = $crsHome unless $confref->{$crsHome}{pre11gr2_config}{crs_home}; } has::Common::clusterConfigCopyVals($confref->{$crsHome}{pre11gr2_config}, $confref->{$crsHome}) if $crsHome and $confref->{$crsHome}{pre11gr2_config}; return $confref; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterNodeListPre11g # # DESC # return a hash of # {nodelist => # nodearray => ) # crs_home => # of nodes in a cluster # # ARGUMENTS # crsHome if known # # RETURNS # hash result list #------------------------------------------------------------------------------ sub hasGetClusterNodeListPre11g(;$) { my ($crsHome ) = @_; # CRSHome my $nodes; my @nodes; my $ncrsHome; my $confref = has::Common::getClusterCacheRef(); if ( $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{node} and $confref->{$crsHome}{node}{nodearray} ) { return $confref; } $crsHome =~ s/^\s+|\s+$//g if $crsHome; undef $crsHome if $crsHome and $crsHome =~ /^\s*$/; # the order of search directories for olsnode/lsnodes my %olsnodeorder; if ( $crsHome ) { $olsnodeorder{0}{path}=$crsHome; $olsnodeorder{0}{cmd}='olsnodes'; } my $discCrsHome = has::Common::hasGetCRSHome(); if ( $discCrsHome ) { $olsnodeorder{1}{path}=$discCrsHome; $olsnodeorder{1}{cmd}='olsnodes'; } $olsnodeorder{2}{path}='CRS_HOME'; $olsnodeorder{2}{cmd}='olsnodes'; $olsnodeorder{3}{path}='EM_CRS_HOME'; $olsnodeorder{3}{cmd}='olsnodes'; $olsnodeorder{4}{path}='ORACLE_HOME'; $olsnodeorder{4}{cmd}='olsnodes'; $olsnodeorder{5}{path}='EMDROOT'; $olsnodeorder{5}{cmd}='lsnodes'; for my $order ( sort {$a <=> $b} keys %olsnodeorder ) { my $path; my $cmd; undef $ncrsHome if $ncrsHome; next unless $olsnodeorder{$order} and $olsnodeorder{$order}{path} and $olsnodeorder{$order}{cmd}; $path = $olsnodeorder{$order}{path}; $path = $ENV{$olsnodeorder{$order}{path}} if $ENV{$olsnodeorder{$order}{path}}; next unless $path; next if $path =~ /#CRS_HOME#|EM_CRS_HOME|CRS_HOME|ORACLE_HOME|EMDROOT/; next unless has::Common::hasIsReadable($path); $cmd = $olsnodeorder{$order}{cmd}; #get the list of nodes using olsnodes my %command_args = (exit_failure_list => [()]); my $fullcmd; for my $ext ( ( 'exe', 'bat' , undef) ) { my $ecmd; $ecmd = "$cmd\.$ext" if $ext; $ecmd = $cmd unless $ecmd; $fullcmd = catfile($path,'bin',$ecmd); stat $fullcmd; last if has::Common::hasIsReadable($fullcmd); undef $fullcmd; } next unless $fullcmd; has::Common::hasSetCRSEnv($path); $nodes = has::Common::runsystemcommand($fullcmd.' 2>&1','',\%command_args); has::Common::hasRestoreCRSEnv(); warn("DEBUG:has::Common::hasGetClusterNodeListPre11g:Failed executing command **$fullcmd") and next if $command_args{command_return_status}; if ( $nodes ) { # bug 4667678 $ncrsHome = $path unless $path =~ /EMDROOT/; warn("DEBUG:has::Common::hasGetClusterNodeListPre11g:Getting node list from $cmd at $path") and last; } } warn("WARN:has::Common::hasGetClusterNodeListPre11g:Failed to get nodelist from cluster binaries olsnodes and cluvfy") and return unless $nodes; chomp($nodes) if $nodes; $nodes=~ s/^\s+|\s+$//g if $nodes; $nodes =~ s/\n/,/g if $nodes; $nodes =~ s/,\s+,/,,/g if $nodes; $nodes =~ s/,+/,/g if $nodes; $nodes=~ s/^,|,$//g if $nodes; return $confref unless $nodes; @nodes = split/,/,$nodes if $nodes; $crsHome = $ncrsHome if $ncrsHome and not $crsHome; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { $confref->{$ch}{node}{nodelist} = $nodes unless $confref->{$ch}{node}{nodelist}; $confref->{$ch}{node}{nodearray} = \@nodes unless $confref->{$ch}{node}{nodearray}; } if ( $crsHome ) { $confref->{$crsHome}{node}{nodelist} = $nodes; $confref->{$crsHome}{node}{nodearray} = \@nodes; $confref->{$crsHome}{node}{crs_home} = $crsHome unless $confref->{$crsHome}{node}{crs_home}; } } else { $crsHome = '#CRS_HOME#' unless $crsHome; $confref->{$crsHome}{node}{nodelist} = $nodes if $nodes; $confref->{$crsHome}{node}{nodearray} = \@nodes if @nodes; $confref->{$crsHome}{node}{crs_home} = $crsHome unless $confref->{$crsHome}{node}{crs_home}; } has::Common::clusterConfigCopyVals($confref->{$crsHome}{node}, $confref->{$crsHome}) if $crsHome and $confref->{$crsHome}{node}; return $confref; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterConfigEmcrsp # # DESC # return the config information for the cluster using emcrsp for 11gR2 clusters # and higher # # ARGUMENTS # crsHome if known # RETURN # ref to the hash to be filled in with values #------------------------------------------------------------------------------ sub hasGetClusterConfigEmcrsp(;$) { # name : hasGetClusterConfigEmcrsp_fn # desc : it filters our the nodename # # arg : # ref to xml element to be filtered #``ref to the result hass entities nodearray # sub hasGetClusterConfigEmcrsp_fn(\%\%) { my ( $elref, $rsref ) = @_; return 1 unless $elref->{element} and $elref->{element} =~ /^(nodename|header|entity)$/i; #$rsref->{nodename}=$elref->{name} and return 1 if $elref->{element} =~ /^nodename$/; if ( $elref->{element} =~ /^nodename$/ ) { $rsref->{node}{nodename}=$elref->{name} if $elref->{name}; return 1; } # if the header is passed , read the cluster_name and crs_version if ( $elref->{element} =~ /^header$/i ) { if ( $elref->{attrs} ) { # read all attribs from # <header crs_version='11.1.0.7.19' dtd_version='1.0' cluster_name ='ajdsouzagcq17has' # ocr_configured='TRUE' ocr_location='CLUSTER'> </header> for my $hdval ( keys %{$elref->{attrs}} ) { $rsref->{$hdval} = $elref->{attrs}{$hdval}; $rsref->{node}{crs_version} = $elref->{attrs}{$hdval} and next if $hdval =~ /^crs_version$/i; $rsref->{node}{cluster_name} = $elref->{attrs}{$hdval} and next if $hdval =~ /^cluster_name$/i; $rsref->{node}{ocr_configured} = $elref->{attrs}{$hdval} and next if $hdval =~ /^ocr_configured$/i; $rsref->{node}{ocr_location} = $elref->{attrs}{$hdval} and next if $hdval =~ /^ocr_location$/i; } } } # if node entity if ( $elref->{element} =~ /^entity$/i ) { my $thisnode; my %nodehash; # return unless entitu is of type entity return 1 unless $elref->{attrs} and $elref->{attrs}{entity_type} and $elref->{attrs}{entity_type} =~ /^node$/; # get the node name if ( $elref->{attrs} ) { # read all attribs from # <entity entity_name='stbdq17' entity_type='node' type='' registered='0'> for my $hdval ( keys %{$elref->{attrs}} ) { $thisnode = $elref->{attrs}{$hdval} if $hdval =~ /^entity_name$/; } } $thisnode =~ s/^\s+|\s+$//g; # read all name=value pairs from the attributes of the node for my $elref1 ( @{$elref->{children}} ) { next unless $elref1->{element} =~ /^attributes$/; for my $elref2 ( @{$elref1->{children}} ) { next unless $elref2->{element} =~ /^attribute$/; my $name; my $value; for my $elref3 ( @{$elref2->{children}} ) { next unless $elref3->{element} =~ /^(name|value)$/; $name = $elref3->{name} if $elref3->{element} =~ /^name$/; $value = $elref3->{name} if $elref3->{element} =~ /^value$/; $name =~ s/^\s+|\s+$//g if $name; $value =~ s/^\s+|\s+$//g if $value; } $nodehash{$name}=$value if $name; } # if you did not get the node name from entity_name try to get it from # attribute name $thisnode = $nodehash{NAME} if not $thisnode and $nodehash{NAME}; next unless $thisnode; # save the node name information for my $nm ( keys %nodehash ) { $rsref->{node}{details}{$thisnode}{$nm}=$nodehash{$nm}; } last; } } return 1; } my ( $crsHome ) = @_; # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { $crsHome = has::Common::hasGetCRSHome(); # get the cluster home by discovery if ( not $crsHome or not has::Common::hasCheckForEmcrsp($crsHome) ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } my $confref = has::Common::getClusterCacheRef(); return $confref and warn "WARN:has::Common::hasGetClusterConfigEmcrsp:Cluster home is not passed or not set in env" unless $crsHome; return $confref and warn "DEBUG:has::Common::hasGetClusterConfigEmcrsp:binary emcrsp is not present in $crsHome" unless has::Common::hasCheckForEmcrsp($crsHome); # set marker that this crsHome has emcrsp so a 11gr2 cluster $confref->{$crsHome}{emcrsp}=1; has::Common::hasSetCRSEnv($crsHome); my $cmdresults = has::Common::runsystemcommand("emcrsp","em config -e node"); has::Common::hasRestoreCRSEnv(); my @ress = split/\n/,$cmdresults if $cmdresults; my $temp_res; for my $resss ( @ress ) { next unless $resss and $resss =~ /^\s*</; $temp_res = '' unless $temp_res; $temp_res = "$temp_res$resss\n"; } $cmdresults = $temp_res if $temp_res; undef $cmdresults unless $temp_res; warn "WARN:has::Common::hasGetClusterConfig Failed to get results from command - emcrsp em config -e node" and return unless $cmdresults; my %xmlvar = has::Common::parse_xml($cmdresults); my %nodeList; has::Common::traverse_xml(\%xmlvar,\&has::Common::has_handle_error,\&hasGetClusterConfigEmcrsp_fn,\%nodeList); $confref->{$crsHome} = \%nodeList; # from node details get the node array and node nodelist if ( $confref and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{node} and $confref->{$crsHome}{node}{details} and keys %{$confref->{$crsHome}{node}{details}} ) { my @nodearray; my $nodelist; for my $nodename ( keys %{$confref->{$crsHome}{node}{details}} ) { $nodename =~ s/^\s+|\s+$//g; next unless $nodename; push @nodearray,$nodename; $nodelist = "$nodelist,$nodename" and next if $nodelist; $nodelist = "$nodename" and next unless $nodelist; # make sure we have NAME and HOST_NAME here as they are keys $confref->{$crsHome}{node}{details}{$nodename}{NAME} = $nodename unless $confref->{$crsHome}{node}{details}{$nodename}{NAME}; $confref->{$crsHome}{node}{details}{$nodename}{HOST_NAME} = $nodename unless $confref->{$crsHome}{node}{details}{$nodename}{HOST_NAME}; $confref->{$crsHome}{node}{details}{$nodename}{crs_home} = $crsHome unless $confref->{$crsHome}{node}{details}{$nodename}{crs_home}; } # for node $confref->{$crsHome}{node}{crs_home} = $crsHome; $confref->{$crsHome}{node}{nodelist} = $nodelist if $nodelist; $confref->{$crsHome}{node}{nodearray} = \@nodearray; } has::Common::clusterConfigCopyVals($confref->{$crsHome}{node}, $confref->{$crsHome}) if $crsHome and $confref->{$crsHome}{node}; return $confref; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterStatus # # DESC # get clusterware status # # ARGUMENTS # list of nodes # CRS Home if available # type ha|crs # # RETURNS # returns a hash ref of results # #------------------------------------------------------------------------------ sub hasGetClusterStatus ( $;$$ ) { my ( $nodes,$crsHome,$type ) = @_; my @nlist; my @fnlist; my $nodearg = ''; my $oldOH; my $confref = has::Common::getClusterCacheRef(); if ( $crsHome ) { $crsHome =~ s/\s+//g; undef $crsHome if $crsHome =~ /^$/ or $crsHome eq ''; } # by default get cluster status $type = 'crs' unless $type and $type =~ /^(ha|crs)$/i; # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { $crsHome = has::Common::hasGetCRSHome(); # get the cluster home by discovery if ( not $crsHome ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } return and warn "WARN:has::Common::hasGetClusterStatus:Cluster home is not passed or not set in env" unless $crsHome; $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 1; $confref->{$crsHome}{cluvfy_status}{failedCount} = 0; $confref->{$crsHome}{cluvfy_status}{successCount} = 0; $confref->{$crsHome}{cluvfy_status}{errCount}=0; @nlist = split(/,/, $nodes) if $nodes; # add onefor the case of cluvfy without -n nodes push(@nlist,'') unless @nlist; if ( $nodes ) { $nodes =~ s/\s+//g; undef $nodes if $nodes =~ /^$/ or $nodes eq ''; $nodearg = " -n $nodes" if $nodes; } warn("DEBUG:has::Common::hasGetClusterStatus:**Node List: $nodearg"); my %command_args = (exit_failure_list => [()],timeout=>290,tries=>1); # execute cluvfy new format with -display_status # ideally this should be a version check so cluvfy is executed only once has::Common::hasSetCRSEnv($crsHome); # trying to set CV directories as instructed by dipak.saggi due to bug in cluvfy # if two cluvfy are executed at the same time then can run on each others stage dir #delete $ENV{CV_DESTLOC} if $ENV{CV_DESTLOC}; #delete $ENV{CV_TRACELOC} if $ENV{CV_TRACELOC}; #my $cvdir = has::Common::has_get_cache_dir() or # warn "WARN:Failed to get a cache dir for setting CV_DESTLOC and CV_TESTLOC for cluvfy"; #if ( $cvdir ) #{ # $cvdir = catfile($cvdir,'clscv'); # my $cvdestloc = catfile($cvdir,'crsdestloc'); # my $cvtraceloc = catfile($cvdir,'crstraceloc'); # $ENV{CV_DESTLOC}=$cvdestloc if $cvdestloc; # $ENV{CV_TRACELOC}=$cvtraceloc if $cvtraceloc; #} $confref->{$crsHome}{cluvfy_status}{o} = has::Common::runsystemcommand( "cluvfy comp $type -display_status $nodearg 2>\&1",'',\%command_args); #delete $ENV{CV_DESTLOC} if $ENV{CV_DESTLOC}; #delete $ENV{CV_TRACELOC} if $ENV{CV_TRACELOC}; has::Common::hasRestoreCRSEnv(); $confref->{$crsHome}{cluvfy_status}{o} =~ s/^\s+|\s+$// if $confref->{$crsHome}{cluvfy_status}{o}; #execute cluvfy new format without -display_status if flag option is not # supported unless ( $confref->{$crsHome}{cluvfy_status}{o} and $confref->{$crsHome}{cluvfy_status}{o} =~ /NODE_STATUS::/i ) { %command_args = (exit_failure_list => [()],timeout=>290,tries=>1); has::Common::hasSetCRSEnv($crsHome); # trying to set CV directories as instructed by dipak.saggi due to bug in cluvfy # if two cluvfy are executed at the same time then can run on each others stage dir #delete $ENV{CV_DESTLOC} if $ENV{CV_DESTLOC}; #delete $ENV{CV_TRACELOC} if $ENV{CV_TRACELOC}; #my $cvdir = has::Common::has_get_cache_dir() or # warn "WARN:Failed to get a cache dir for setting CV_DESTLOC and CV_TESTLOC for cluvfy"; #if ( $cvdir ) #{ # $cvdir = catfile($cvdir,'clscv'); # my $cvdestloc = catfile($cvdir,'crsdestloc'); # my $cvtraceloc = catfile($cvdir,'crstraceloc'); # $ENV{CV_DESTLOC}=$cvdestloc if $cvdestloc; # $ENV{CV_TRACELOC}=$cvtraceloc if $cvtraceloc; #} $confref->{$crsHome}{cluvfy_status}{o} = has::Common::runsystemcommand( "cluvfy comp $type $nodearg 2>\&1",'',\%command_args); #delete $ENV{CV_DESTLOC} if $ENV{CV_DESTLOC}; #delete $ENV{CV_TRACELOC} if $ENV{CV_TRACELOC}; has::Common::hasRestoreCRSEnv(); $confref->{$crsHome}{cluvfy_status}{o} =~ s/^\s+|\s+$// if $confref->{$crsHome}{cluvfy_status}{o}; } chomp($confref->{$crsHome}{cluvfy_status}{o}) if $confref->{$crsHome}{cluvfy_status}{o}; $confref->{$crsHome}{cluvfy_status}{o} =~ s/\n/,/g if $confref->{$crsHome}{cluvfy_status}{o}; $confref->{$crsHome}{cluvfy_status}{o} =~ s/\cM//g if $confref->{$crsHome}{cluvfy_status}{o}; die("ERROR:has::Common::hasGetClusterStatus:crs_status_cluster.pl:Failed to get any results from cluvfy comp $type -n $nodearg") unless $confref->{$crsHome}{cluvfy_status} and $confref->{$crsHome}{cluvfy_status}{o}; # output with -display_status flag # cluvfy comp crs -display_status -n staca31 #NODE_STATUS::Node1:SUCC #NODE_STATUS::Node2:EFAIL #NODE_STATUS::Node3:VFAIL #NODE_STATUS::Node4:SUCC #OVERALL_STATUS::EFAIL # if cluvfy comp crs -n node1, node2 does not return a success # for all nodes the exit status is failure for ( (1) ) { # crs is up if cluvfy did not return a failure unless ( $command_args{command_return_status} ) { $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 1; $confref->{$crsHome}{cluvfy_status}{failedCount}=0; $confref->{$crsHome}{cluvfy_status}{successCount}=@nlist; last; } #------------------------------------------------------------------ # check for failed nodes etc only if the cluvfy returned a failure #------------------------------------------------------------------ # # for pre11g version we are trying to get the list of failed nodes # from the cli output using the following logic # cluvfy comp crs -n <nodes> # a) fails on all nodes # Verification of CRS integrity was unsuccessful on all the nodes. # b) partial failure , fails on some nodes # Verification of CRS integrity was unsuccessful. # checks did nto pass for the following node(s): # node1,node2 # c)all successful # Verification of CRS integrity was successful # # email sent by dipak.saggi confirming the messages # "Verification of {0} was unsuccessful on all the nodes. " # "Verification of {0} was unsuccessful. " # "Checks did not pass for the following node(s):" # my $with_node_status_for_em = 'NODE_STATUS::|OVERALL_STATUS::'; my $failed_on_some_nodes= 'Checks\s+did\s+not\s+pass\s+for\s+the\s+following\s+node\(s\):'; my $failed_on_all_nodes = 'unsuccessful\s+on\s+all\s+the\s+nodes'; my $error_executing_cluvfy = 'ERROR:|CRS\s+is\s+not\s+installed\s+on\s+any\s+of\s+the\s+nodes|Verification\s+cannot\s+proceed|User\s+equivalence\s+is\s+not\s+set\s+for\s+nodes'; # if cluvfy supports the displsy_status flag and gives NODE_STATUS if ( $confref->{$crsHome}{cluvfy_status}{o} =~ /$with_node_status_for_em/ ) { my @inp = split /\n/,$confref->{$crsHome}{cluvfy_status}{o}; my @rows = grep /$with_node_status_for_em/, @inp; my $nodeVerificationFailed; for my $row ( @rows ) { $row =~ s/^\s+|\s+$//; #success $confref->{$crsHome}{cluvfy_status}{successCount} +=1 and next if $row and $row =~ /NODE_STATUS::.+:SUCC$/; #if command returns overall success, then take the results of overall # and declare crs is up on all nodes if ( $row and $row =~ /OVERALL_STATUS::SUCC/ ) { $confref->{$crsHome}{cluvfy_status}{crsIsUp}=1; $confref->{$crsHome}{cluvfy_status}{failedCount}=0; $confref->{$crsHome}{cluvfy_status}{successCount} = @nlist; last; } # verification failed, increment failed count $confref->{$crsHome}{cluvfy_status}{failedCount} +=1 and next if $row =~ /NODE_STATUS::.+:VFAIL/; # execution failure next unless $row =~ /NODE_STATUS::.+:EFAIL/; $confref->{$crsHome}{cluvfy_status}{errCount} += 1; my ($node) = ( $row =~ /NODE_STATUS::(.+):EFAIL/); warn("WARN:has::Common::hasGetClusterStatus Failed to get node name from execution failure of cluvfy while checking Clusterware Status $row\n") and next unless $node; $nodeVerificationFailed = "$nodeVerificationFailed,$node" and next if $nodeVerificationFailed; $nodeVerificationFailed = "$node" unless $nodeVerificationFailed; } warn("WARN:has::Common::hasGetClusterStatus Status verification failed due to cluvfy execution failure for node(s) $nodeVerificationFailed\n") if $nodeVerificationFailed; # crs is down if all nodes failed or failed count is > nodes $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 0 if scalar(@nlist) == $confref->{$crsHome}{cluvfy_status}{failedCount}; $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 0 unless $confref->{$crsHome}{cluvfy_status}{successCount}; } elsif ($confref->{$crsHome}{cluvfy_status}{o} =~ /$failed_on_some_nodes/i) { my $fo = $confref->{$crsHome}{cluvfy_status}{o}; $fo =~ s/\n+/,/g; my ($ignore,$fnodes) = ( $fo =~ /.*($failed_on_some_nodes)(.*)$/i); $fnodes =~ s/,\s+,/,/g; $fnodes =~ s/,+/,/g; $fnodes =~ s/^\s+|\s+$//; $fnodes =~ s/^,+|,+$//; warn("DEBUG:has::Common::hasGetClusterStatus:crs_status_cluster.pl:**failed node list:($fnodes)"); @fnlist = split(/,/, $fnodes); $confref->{$crsHome}{cluvfy_status}{failedCount} = scalar(@fnlist); # if crs is up on atleast one node then crs is up if ( scalar(@nlist) == scalar (@fnlist) ) { $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 0; last; } $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 1; last; } elsif ($confref->{$crsHome}{cluvfy_status}{o} =~ /$failed_on_all_nodes/i ) { $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 0; $confref->{$crsHome}{cluvfy_status}{failedCount}=scalar(@nlist); last; } elsif ($confref->{$crsHome}{cluvfy_status}{o} =~ /$error_executing_cluvfy/i ) { $confref->{$crsHome}{cluvfy_status}{crsIsUp}=2; $confref->{$crsHome}{cluvfy_status}{failedCount}=scalar(@nlist); warn("WARN:has::Common::hasGetClusterStatus Failed to get Status for cluster, CRS verification failed for cluster $confref->{$crsHome}{cluvfy_status}{o}\n"); last; } else { $confref->{$crsHome}{cluvfy_status}{crsIsUp} = 2; $confref->{$crsHome}{cluvfy_status}{failedCount}=scalar(@nlist); warn("WARN:has::Common::hasGetClusterStatus Failed to get Status for cluster , CRS verification failed for cluster $confref->{$crsHome}{cluvfy_status}{o}\n"); last; } } $confref->{$crsHome}{crs_home} = $crsHome if $crsHome and not $confref->{$crsHome}{crs_home}; return $confref->{$crsHome}{cluvfy_status}; } #------------------------------------------------------------------------------ # FUNCTION : hasClusterHealthCheck # # DESC # get clusterware health check status # # ARGUMENTS # CRS Home if available # type = crs # # RETURNS # returns a hash ref of results # #------------------------------------------------------------------------------ sub hasClusterHealthCheck ( $;$ ) { my ( $type,$crsHome ) = @_; my %clshm; my $with_node_status_for_em = 'NODE_STATUS:|OVERALL_STATUS::'; if ( $crsHome ) { $crsHome =~ s/\s+//g; undef $crsHome if $crsHome =~ /^$/ or $crsHome eq ''; } # by default get cluster status $type = 'crs' unless $type and $type =~ /^(ha|crs)$/i; # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { $crsHome = has::Common::hasGetCRSHome(); # get the cluster home by discovery if ( not $crsHome ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } return and warn "WARN:has::Common::hasClusterHealthCheck:Cluster home is not passed or not set in env" unless $crsHome; my %command_args = (exit_failure_list => [()],timeout=>290,tries=>1); my $results; # execute cluvfy new format with -display_status # ideally this should be a version check so cluvfy is executed only once has::Common::hasSetCRSEnv($crsHome); # trying to set CV directories as instructed by dipak.saggi due to bug in cluvfy # if two cluvfy are executed at the same time then can run on each others stage dir #delete $ENV{CV_DESTLOC} if $ENV{CV_DESTLOC}; #delete $ENV{CV_TRACELOC} if $ENV{CV_TRACELOC}; #my $cvdir = has::Common::has_get_cache_dir() or # warn "WARN:Failed to get a cache dir for setting CV_DESTLOC and CV_TESTLOC for cluvfy"; #if ( $cvdir ) #{ # $cvdir = catfile($cvdir,'clshc'); # my $cvdestloc = catfile($cvdir,'crsdestloc'); # my $cvtraceloc = catfile($cvdir,'crstraceloc'); # $ENV{CV_DESTLOC}=$cvdestloc if $cvdestloc; # $ENV{CV_TRACELOC}=$cvtraceloc if $cvtraceloc; #} $results = has::Common::runsystemcommand( "cluvfy comp health -_format 2>\&1",'',\%command_args); #delete $ENV{CV_DESTLOC} if $ENV{CV_DESTLOC}; #delete $ENV{CV_TRACELOC} if $ENV{CV_TRACELOC}; has::Common::hasRestoreCRSEnv(); # warn "ERROR::has::Common::hasClusterHealthCheck:Failed executing the cluster health check command cluvfy comp health \n" and return if $command_args{command_return_status}; chomp $results if $results; $results =~ s/^\s+|\s+$// if $results; chomp $results if $results; $results =~ s/^\s+|\s+$// if $results; $results =~ s/\cM//g if $results; warn "ERROR::has::Common::hasClusterHealthCheck:Failed to get results for cluster health check from cluvfy comp health \n" and return unless $results; my @results = split/\n/,$results; # if cluvfy comp crs -n node1, node2 does not return a success # for all nodes the exit status is failure my %description; my $current_component; my $current_message; my $i=0; for my $res ( @results ) { $res =~ s/^\s+|\s+$//g if $res; next unless $res; # if cluvfy supports the displsy_status flag and gives NODE_STATUS if ( $res =~ /$with_node_status_for_em/ ) { my ( $component,$node,$status,$description) = split/::/,$res; warn "WARN::has::Common::hasClusterHealthCheck:Failed to read the component and status from $res" and next unless $component or $node or $status; if ( $description ) { $description{$component}=$description; } if ( $node =~/NODE_STATUS:/ ) { my ( $node_name ) = ( $node =~ /NODE_STATUS:(.*)$/); warn "WARN::has::Common::hasClusterHealthCheck:Failed to read the node name from $node" unless $node_name; $node = "$node_name" if $node_name; } elsif ( $node =~/OVERALL_STATUS/ ) { $node = 'Cluster'; } $current_component="$component\_$node"; $clshm{$current_component}{elem_attribs}{GENERATED_KEY_1}="$component\_$node"; $clshm{$current_component}{elem_attribs}{CRS_COMPONENT}="$component"; $clshm{$current_component}{elem_attribs}{DEDUCED_COMPONENT_STATUS}="$status"; if ( $status =~ /SUCC/ ) { $clshm{$current_component}{elem_attribs}{COMPONENT_STATUS}="$status"; } if ( $status =~ /SUCC/ ) { $clshm{$current_component}{elem_attribs}{COMPONENT_STATUS_MESSAGE}='Successful'; } elsif ( $status =~ /VFAIL/ ) { $clshm{$current_component}{elem_attribs}{COMPONENT_STATUS_MESSAGE}='Failed'; } elsif ( $status =~ /EFAIL/ ) { $clshm{$current_component}{elem_attribs}{COMPONENT_STATUS_MESSAGE}='Execution Failed'; } elsif ( $status =~ /WARN/ ) { $clshm{$current_component}{elem_attribs}{COMPONENT_STATUS_MESSAGE}='Warning'; } else { $clshm{$current_component}{elem_attribs}{COMPONENT_STATUS_MESSAGE}='Unknown'; } $clshm{$current_component}{elem_attribs}{NODE_NAME}="$node"; $clshm{$current_component}{elem_attribs}{COMPONENT_DESCRIPTION}=$description{$component} if $description{$component}; } elsif ($res =~ /^MSG_START/i) { undef $current_message; $i = 0; } elsif ( $res =~ /^MSG_END/i ) { $clshm{$current_component}{elem_attribs}{COMPONENT_STATUS}= $clshm{$current_component}{elem_attribs}{DEDUCED_COMPONENT_STATUS} if $clshm{$current_component}{elem_attribs}{DEDUCED_COMPONENT_STATUS}; if ( $current_message ) { warn "WARN::has::Common::hasClusterHealthCheck:Failed to get the component for error message $current_message\n" unless $current_component; } else { warn "WARN::has::Common::hasClusterHealthCheck:Failed to get the component for $res\n" unless $current_component; } $clshm{$current_component}{elem_attribs}{ERROR_MESSAGE}=$current_message; undef $current_message; undef $current_component; $i=0; } else { if ( $res =~ /^PRVF-/ ) { $i++; $res = "($i) $res"; } if ( $current_message ) { $current_message = "$current_message $res"; } else { $current_message = $res; } } } return \%clshm; } #------------------------------------------------------------------------------ # FUNCTION : getClusterCacheRef # # DESC # return the ref for config information for the cluster # # ARGUMENTS # RETURN # ref for config information for the cluster #------------------------------------------------------------------------------ sub getClusterCacheRef() { return \%has::Common::hasClusterConfig; } #------------------------------------------------------------------------------ # FUNCTION : clusterConfigCopyVals # # DESC # copy the list of cluster properties between the two lists passed # # ARGUMENTS # RETURN # source ref to copy from config information for the cluster # destination ref to copy to config information for the cluste #------------------------------------------------------------------------------ sub clusterConfigCopyVals($$;) { my ( $source_ref,$dest_ref) = @_; for my $prop ( qw ( crs_home nodelist nodearray crs_version version vendor isvendorcw nodename host_name cluster_name emcrsp ) ) { next if ( not $source_ref or not defined $source_ref->{$prop} ) and ( not $dest_ref or not defined $dest_ref->{$prop} ); if ( not $dest_ref or not defined $dest_ref->{$prop} ) { $dest_ref->{$prop} = $source_ref->{$prop} if $source_ref and $source_ref->{$prop}; } if ( not $source_ref or not defined $source_ref->{$prop} ) { $source_ref->{$prop} = $dest_ref->{$prop} if $dest_ref and $dest_ref->{$prop}; } } return 1; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterConfig # # DESC # return the config information for the cluster # # ARGUMENTS # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # RETURNS # ref to the hash to be filled in with values #------------------------------------------------------------------------------ #the structure returned is #it can hold information for multiple crs_homes which is required in dev # environments # # cluster information from cli or emcrsp # {<home_dir>}=(crs_home,cluster_name,host_name,nodelist,nodearray,nodename,host_name, # vendor,isvendorcw,crs_version,version,emcrsp) # # local node information from cli or emcrsp # {<home_dir>}{pre11gr2_config} = {crs_home,nodename,host_name,vendor,isvendorcw, # crs_version,version,nodelist,nodearray} # # discovered information # {<home_dir>}{discover}{nodes}{<nodename>} # {<home_dir>}{discover}{crs_home} # {<home_dir>}{discover}{cluster_name} # {<home_dir>}{discover}{nodelist} # {<home_dir>}{discover}{nodearray} # # node information from cli lsnode or emcrsp # {<home_dir>}{node}{details}{<nodename>}={NAME,HOST_NAME,NODE_NUM,} # {<home_dir>}{node}{crs_home} # {<home_dir>}{node}{cluster_name} # {<home_dir>}{node}{nodearray} # {<home_dir>}{node}{nodelist} # sub hasGetClusterConfig(;$$) { my ( $crsHome,$dynProp ) = @_; my $confref; $confref = has::Common::getClusterCacheRef(); $crsHome =~ s/\s+//g if $crsHome; undef $crsHome if $crsHome and $crsHome =~ /^\s*$/; # values already cached then return it back if ( $confref and ref($confref) and keys %{$confref} ) { if ( $crsHome ) { if ( $confref->{$crsHome} ) { my $flag = 1; for my $prop ( qw ( crs_home nodelist nodearray crs_version version vendor isvendorcw nodename host_name cluster_name emcrsp ) ) { next if defined $confref->{$crsHome}{$prop}; $flag = 0; last; } return $confref if $flag; } } # if there is no entry for the passed crs home then check for others # the assumption that there is only one crsHome or one cluster per box else { # values already cached then return it back for my $ch ( keys %{$confref} ) { my $flag = 1; for my $prop ( qw ( crs_home nodelist nodearray crs_version version vendor isvendorcw nodename host_name cluster_name emcrsp ) ) { next if defined $confref->{$ch}{$prop}; $flag = 0; last; } return $confref if $flag; } } } # start with discovery , populates the discover structure $confref = has::Common::hasDiscoverCluster(); for my $ch ( keys %{$confref} ) { next unless $confref->{$ch}{discover}; has::Common::clusterConfigCopyVals($confref->{$ch}{discover},$confref->{$ch}); } my @chomes; # if a crs home is passed get config only by passing that crs home # if no crs home is passed use discovery if ( $crsHome ) { push @chomes,$crsHome; } else { @chomes = keys %{$confref}; } if ( not @chomes ) { my $crsEnvHome = has::Common::hasGetEnvCRSHome(); push @chomes, $crsEnvHome if $crsEnvHome; } # for each cluster home get the values for my $ch ( @chomes ) { # get he 11g node list crsctl/cemutl stuff, pupulates pre11gr2_config $confref = has::Common::hasGetClusterConfigPre11g($ch,$dynProp); # get the 11g local nodename using olsnodes -l , populates pre11gr2_config $confref = has::Common::hasGetClusterGetNodeNamePre11g($ch); has::Common::clusterConfigCopyVals($confref->{$ch}{pre11gr2_config}, $confref->{$ch}) if $confref->{$ch}{pre11gr2_config}; # get the 11g node list from olsnodes populates the node element $confref = has::Common::hasGetClusterNodeListPre11g($ch) unless $confref->{$ch}{node} and $confref->{$ch}{node}{nodearray} and $confref->{$ch}{node}{nodelist}; has::Common::clusterConfigCopyVals($confref->{$ch}{node}, $confref->{$ch}) if $confref->{$ch}{node}; # get the local node name my $nodename = $confref->{$ch}{nodename} if $confref->{$ch}{nodename}; # get the local host name $confref->{$ch}{host_name} = has::Common::hasGetLocalHostName() unless $confref->{$ch}{host_name}; my $hostname = $confref->{$ch}{host_name} if $confref->{$ch}{host_name}; # get the node list to build node details from 11gR1 olsnodes list if ( keys %{$confref->{$ch}} and $confref->{$ch}{nodearray} ) { for my $node ( @{$confref->{$ch}{nodearray}} ) { $confref->{$ch}{node}{details}{$node}{NAME}=$node; # if this is the current node then get hostname $confref->{$ch}{node}{details}{$node}{HOST_NAME}=$node if $hostname and $nodename and $node =~ /^$nodename$/ and not $confref->{$ch}{node}{details}{$node}{HOST_NAME}; # TBD if this is the current node then get hostname # css api should provide the host name for each nodename $confref->{$ch}{node}{details}{$node}{HOST_NAME}=$node if not $confref->{$ch}{node}{details}{$node}{HOST_NAME}; $confref->{$ch}{node}{details}{$node}{crs_home}=$ch unless $confref->{$ch}{node}{details}{$node}{crs_home}; } } # get the node name $confref = has::Common::hasGetClusterGetNodeNamePre11g($ch) unless $confref->{$ch}{nodename}; # do the 11 discovery using emcrsp $confref = has::Common::hasGetClusterConfigEmcrsp($ch); # synchronize the top vales from all the sub lists # discover - from discovery # pre11gr2_config - from cemutl,crsctl, olsnode # node - from emcrsp,olsnode has::Common::clusterConfigCopyVals($confref->{$ch}{node}, $confref->{$ch}) if $confref->{$ch}{node}; has::Common::clusterConfigCopyVals($confref->{$ch}{pre11gr2_config},$confref->{$ch}) if $confref->{$ch}{pre11gr2_config}; has::Common::clusterConfigCopyVals($confref->{$ch}{discover},$confref->{$ch}) if $confref->{$ch}{discover}; } return $confref; } #------------------------------------------------------------------------------ # FUNCTION : hasGetNodeName # # DESC # return the node name for the local node # # ARGUMENTS # crsHome if known #------------------------------------------------------------------------------ sub hasGetNodeName(;$) { my ( $crsHome, $dynProp ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{nodename} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{nodename}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{nodename} if $confref->{$ch}{nodename}; } } $confref = has::Common::hasGetClusterConfig($crsHome,$dynProp); return $confref->{$crsHome}{nodename} if $confref and $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{nodename}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{nodename} if $confref->{$ch}{nodename}; } } warn "WARN:has::Common::hasGetNodeName Failed to get the node name for the cluster node, trying to get hostname"; my $hostName = has::Common::hasGetLocalHostName(); if ( $hostName ) { $hostName =~ s/\..*//; $hostName = lc $hostName if $hostName; } warn "WARN:has::Common::hasGetNodeName Failed to get the node name for the cluster node" and return unless $hostName; return $hostName; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterName # # DESC # return the Cluster Name # # ARGUMENTS # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # #------------------------------------------------------------------------------ sub hasGetClusterName(;$$) { my ( $crsHome,$dynProp ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{cluster_name} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{cluster_name}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{cluster_name} if $confref->{$ch}{cluster_name}; } } if ( $dynProp ) { $confref = has::Common::hasGetClusterConfigPre11g($crsHome,$dynProp); return $confref->{$crsHome}{cluster_name} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{cluster_name}; return; } $confref = has::Common::hasGetClusterConfig($crsHome); return $confref->{$crsHome}{cluster_name} if $confref and $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{cluster_name}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{cluster_name} if $confref->{$ch}{cluster_name}; } } warn "WARN:has::Common::hasGetClusterName Failed to get the cluster name for the cluster "; my $cookedName; if ( ( $ENV{EM_TARGET_TYPE} and $ENV{EM_TARGET_TYPE} =~ /cluster|has/i ) or ( $ENV{TARGET_TYPE} and $ENV{TARGET_TYPE} =~ /cluster|has/i ) ) { $cookedName = $ENV{TARGET_NAME} if $ENV{TARGET_NAME}; $cookedName = $ENV{EM_TARGET_NAME} if $ENV{EM_TARGET_NAME}; } my $hostname = has::Common::hasGetLocalHostName() unless $cookedName; $cookedName = "host_$hostname" if $hostname and not $cookedName; return $cookedName if $cookedName; return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetNodeList # # DESC # return the coma seperated list of nodes # # ARGUMENTS # crsHome if known # #------------------------------------------------------------------------------ sub hasGetNodeList(;$) { my ( $crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{nodelist} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{nodelist}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{nodelist} if $confref->{$ch}{nodelist}; } } $confref = has::Common::hasGetClusterConfig($crsHome); return $confref->{$crsHome}{nodelist} if $confref and $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{nodelist}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{nodelist} if $confref->{$ch}{nodelist}; } } warn "WARN:has::Common::hasGetNodeList Failed to get list of nodes" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetNodeStatus # # DESC # return the status for the node passed or local node is null # # ARGUMENTS # crsHome if known # nodeName is known # #------------------------------------------------------------------------------ sub hasGetNodeStatus(;$$) { my ( $crsHome,$nodeName ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{nodestatus} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{nodestatus}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{nodestatus} if $confref->{$ch}{nodestatus}; } } $confref = has::Common::hasGetClusterConfig($crsHome); return $confref->{$crsHome}{nodestatus} if $confref and $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{nodestatus}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{nodestatus} if $confref->{$ch}{nodestatus}; } } warn "DEBUG:has::Common::hasGetNodeStatus Failed to get status for node" and return unless $nodeName; warn "DEBUG:has::Common::hasGetNodeStatus Failed to get status for node $nodeName" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterVersion # # DESC # return the Clusterware Acive Version # # ARGUMENTS # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # #------------------------------------------------------------------------------ sub hasGetClusterVersion(;$$) { my ( $crsHome,$dynProp ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{crs_version} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{crs_version}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{crs_version} if $confref->{$ch}{crs_version}; } } if ( $dynProp ) { $confref = has::Common::hasGetClusterConfigPre11g($crsHome,$dynProp); return $confref->{$crsHome}{crs_version} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{crs_version}; warn "WARN:has::Common::hasGetClusterVersion Failed to get cluster active version " and return; } $confref = has::Common::hasGetClusterConfig($crsHome); return $confref->{$crsHome}{crs_version} if $confref and $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{crs_version}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{crs_version} if $confref->{$ch}{crs_version}; } } warn "WARN:has::Common::hasGetClusterVersion Failed to get cluster active version " and return; } sub hasGetClusterActiveVersion(;$$) { my ( $crsHome,$dynProp ) = @_; if ( $dynProp ) { return hasGetClusterVersion($crsHome,$dynProp); } else { return hasGetClusterVersion($crsHome); } } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterVendor # # DESC # return the cluster vendor # # ARGUMENTS # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # # RETURNS # vendor name #------------------------------------------------------------------------------ sub hasGetClusterVendor(;$$) { my ( $crsHome,$dynProp ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{vendor} if $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{vendor}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{vendor} if $confref->{$ch}{vendor}; } } if ( $dynProp ) { $confref = has::Common::hasGetClusterConfigPre11g($crsHome,$dynProp); } else { $confref = has::Common::hasGetClusterConfig($crsHome); } return $confref->{$crsHome}{vendor} if $confref and $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{vendor}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{vendor} if $confref->{$ch}{vendor}; } } warn "DEBUG:has::Common::hasGetClusterVendor Failed to get Vendor Name" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetIsVendorCluster # # DESC # return 1 if vendor cluster , 0 for oracle # # ARGUMENTS # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # # RETURNS # 1 or 0 #------------------------------------------------------------------------------ sub hasGetIsVendorCluster(;$$) { my ( $crsHome,$dynProp ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{isvendorcw} if $crsHome and $confref->{$crsHome} and defined $confref->{$crsHome}{isvendorcw}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{isvendorcw} if defined $confref->{$ch}{isvendorcw}; } } if ( $dynProp ) { $confref = has::Common::hasGetClusterConfigPre11g($crsHome,$dynProp); } else { $confref = has::Common::hasGetClusterConfig($crsHome); } return $confref->{$crsHome}{isvendorcw} if $confref and $crsHome and $confref->{$crsHome} and defined $confref->{$crsHome}{isvendorcw}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{isvendorcw} if defined $confref->{$ch}{nodename}; } } warn "DEBUG:has::Common::hasGetIsVendorCluster Failed to check if Vendor clusterware" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterSoftwareVersion # # DESC # return the software version for a node # # ARGUMENTS # node name or null for local node # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # # RETURNS # cluster software version for that node #------------------------------------------------------------------------------ sub hasGetClusterSoftwareVersion(;$$$) { my ( $nodename,$crsHome,$dynProp ) = @_; my $activ_version; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{node}{details}{$nodename}{version} if $nodename and $crsHome and $confref->{$crsHome}{node} and $confref->{$crsHome}{node}{details} and $confref->{$crsHome}{node}{details}{$nodename} and $confref->{$crsHome}{node}{details}{$nodename}{version}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( %{$confref} ) { return $confref->{$ch}{node}{details}{$nodename}{version} if $nodename and $confref->{$ch}{node} and $confref->{$ch}{node}{details} and $confref->{$ch}{node}{details}{$nodename} and $confref->{$ch}{node}{details}{$nodename}{version}; } } if ( $dynProp ) { $confref = has::Common::hasGetClusterConfigPre11g($crsHome,$dynProp); return $confref->{$crsHome}{node}{details}{$nodename}{version} if $nodename and $crsHome and $confref->{$crsHome}{node} and $confref->{$crsHome}{node}{details} and $confref->{$crsHome}{node}{details}{$nodename} and $confref->{$crsHome}{node}{details}{$nodename}{version}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( %{$confref} ) { return $confref->{$ch}{node}{details}{$nodename}{version} if $nodename and $confref->{$ch}{node} and $confref->{$ch}{node}{details} and $confref->{$ch}{node}{details}{$nodename} and $confref->{$ch}{node}{details}{$nodename}{version}; } } $activ_version = has::Common::hasGetClusterActiveVersion($crsHome,$dynProp); } else { $confref = has::Common::hasGetClusterConfig($crsHome); return $confref->{$crsHome}{node}{details}{$nodename}{version} if $nodename and $crsHome and $confref->{$crsHome}{node} and $confref->{$crsHome}{node}{details} and $confref->{$crsHome}{node}{details}{$nodename} and $confref->{$crsHome}{node}{details}{$nodename}{version}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{node}{details}{$nodename}{version} if $nodename and $confref->{$ch}{node} and $confref->{$ch}{node}{details} and $confref->{$ch}{node}{details}{$nodename} and $confref->{$ch}{node}{details}{$nodename}{version}; } } $activ_version = has::Common::hasGetClusterActiveVersion($crsHome); } # return active version if software version is not available if ( $activ_version ) { warn "DEBUG:has::Common::hasGetClusterSoftwareVersion Failed to get software version for node $nodename, returning active version" if $nodename; warn "DEBUG:has::Common::hasGetClusterSoftwareVersion Failed to get software version for local node, returning active version"; return $activ_version; } warn "WARN:has::Common::hasGetClusterSoftwareVersion Failed to get software version for node $nodename" and return if $nodename; warn "WARN:has::Common::hasGetClusterSoftwareVersion Failed to get software version for local node" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetOcrType # # DESC # return if OCR type is has or cluster # # ARGUMENTS # crsHome if known # dynamicProperty - not null valud if function is called for dynamic prop # computation # #------------------------------------------------------------------------------ sub hasGetOcrType(;$$) { # compute ocr type based on output from emcrsp sub computeOcrType($) { my ( $ref ) = @_; return unless $ref and keys %{$ref}; return $ref->{ocr_type} if $ref->{ocr_type}; return unless $ref->{ocr_configured} and $ref->{ocr_location}; if ( $ref->{ocr_configured} =~ /TRUE/ and $ref->{ocr_location} =~ /CLUSTER/ ) { $ref->{ocr_type} = 'cluster'; } elsif ( $ref->{ocr_location} =~ /CLUSTER/ ) { $ref->{ocr_type} = 'cluster'; } elsif ( $ref->{ocr_location} =~ /LOCAL/ ) { $ref->{ocr_type} = 'has'; } else { $ref->{ocr_type} = 'cluster'; } } my ( $crsHome,$dynProp ) = @_; my $confref = has::Common::getClusterCacheRef(); my $o; $o = computeOcrType($confref->{$crsHome}) if $crsHome and $confref->{$crsHome}; # a siha home should have emcrsp as it is 11gr2 code if ( $crsHome ) { $o = 'cluster' unless has::Common::hasCheckForEmcrsp($crsHome); } return $o if $o; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { $o = computeOcrType($confref->{$ch}); $o = 'cluster' unless has::Common::hasCheckForEmcrsp($ch); return $o if $o; } } # if this is for dynamic prop then get the emcrsp config information # only and not all the other config info if ( $dynProp ) { $confref = has::Common::hasGetClusterConfigEmcrsp($crsHome); } else { $confref = has::Common::hasGetClusterConfig($crsHome,$dynProp); } $o = computeOcrType($confref->{$crsHome}) if $confref and $crsHome and $confref->{$crsHome}; if ( $crsHome ) { $o = 'cluster' unless has::Common::hasCheckForEmcrsp($crsHome); } return $o if $o; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { $o = computeOcrType($confref->{$ch}); $o = 'cluster' unless has::Common::hasCheckForEmcrsp($ch); return $o if $o; } } warn "DEBUG:has::Common::hasGetOcrType:Failed to get OCR type, defaulting to a cluster"; return 'cluster'; } #------------------------------------------------------------------------------ # FUNCTION : hasGetClusterNodes # # DESC # return a has list of cluster nodes with config information # # ARGUMENTS # crsHome if known # # RETURNS # return a hash of nodes #------------------------------------------------------------------------------ sub hasGetClusterNodes(;$) { my ( $crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{node} if $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{node} and $confref->{$crsHome}{node}{details}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{node} if $confref->{$ch} and $confref->{$ch}{node} and $confref->{$ch}{node}{details}; } } $confref = has::Common::hasGetClusterConfig($crsHome); return $confref->{$crsHome}{node} if $confref and $crsHome and $confref->{$crsHome} and $confref->{$crsHome}{node} and $confref->{$crsHome}{node}{details}; if ( $confref and $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{node} if $confref->{$ch}{node} and $confref->{$ch}{node}{details}; } } warn "WARN:has::Common::hasGetClusterNodes:Failed to get the list of nodes for cluster" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetScanInformation # # DESC # return the scan Information # # ARGUMENTS # crsHome if known # # RETURNS # hash for results #------------------------------------------------------------------------------ sub hasGetScanInformation(;$) { my ( $crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{scan} if $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{scan}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{scan} if $confref->{$ch} and $confref->{$ch}{scan}; } } if ( not has::Common::hasCheckForEmcrsp($crsHome) ) { warn "WARN:has::Common::hasGetScanInformation:This is a pre 11gR2 cluster, binary emcrsp is not found, no Scan information"; return; } # get the scan information my %meta; $meta{cmd}='emcrsp em config -e resource -p ora.scan_listener.type'; $meta{element_name}='entity'; $meta{entity}{attrs}{entity_name}=1; $meta{entity}{name_value}{NAME}=1; $meta{entity}{name_value}{ID}=1; $meta{entity}{name_value}{IP}=1; $meta{entity}{name_value}{PORT}=1; $meta{entity}{name_value}{TYPE}=1; $meta{entity}{name_value}{BASE_TYPE}=1; $meta{entity}{name_value}{HOSTING_MEMBERS}=1; $meta{entity}{name_value}{LAST_SERVER}=1; $meta{entity}{name_value}{VERSION}=1; my $resref; $resref = has::Common::hasGetEntityInformation(\%meta,$crsHome); # if we have eons data then farm the fields to make sure we have reqd data if ( keys %{$resref} ) { for my $id ( keys %{$resref} ) { $resref->{$id}{SCAN_NAME} = $resref->{$id}{NAME} if $resref->{$id}{NAME} and not $resref->{$id}{SCAN_NAME}; $resref->{$id}{SCAN_NAME} = $resref->{$id}{ID} if $resref->{$id}{ID} and not $resref->{$id}{SCAN_NAME}; $resref->{$id}{SCAN_NAME} = $resref->{$id}{entity_name} if $resref->{entity_name} and not $resref->{$id}{SCAN_NAME}; $resref->{$id}{SCAN_NAME} = 'ora.scan UNKNOWN' unless $resref->{$id} and $resref->{$id}{SCAN_NAME}; $resref->{$id}{SCAN_PORT} = $resref->{$id}{PORT} if defined $resref->{$id}{PORT}; $resref->{$id}{SCAN_PORT} = 0 unless $resref->{$id} and defined $resref->{$id}{SCAN_PORT}; $resref->{$id}{SCAN_IP} = $resref->{$id}{IP} if defined $resref->{$id}{IP}; $resref->{$id}{SCAN_IP}='scanIP_TBD' unless $resref->{$id} and $resref->{$id}{SCAN_IP}; warn "WARN:has::Common::hasGetScanInformation Failed to get NAME for scan resource" unless $resref->{$id} and $resref->{$id}{SCAN_NAME}; warn "WARN:has::Common::hasGetScanInformation Failed to get SCAN PORT for scan resource" unless $resref->{$id} and $resref->{$id}{SCAN_PORT}; warn "WARN:has::Common::hasGetScanInformation Failed to get SCAN IP for scan resource" unless $resref->{$id} and $resref->{$id}{SCAN_IP}; } } else { warn "WARN:has::Common::hasGetScanInformation Failed to get information for scan resource"; $resref->{NO_ID}{SCAN_NAME} = 'ora.scan UNKNOWN'; $resref->{NO_ID}{SCAN_PORT} = undef; $resref->{NO_ID}{SCAN_IP}='scanIP_TBD'; } if ( $crsHome ) { for my $id ( keys %{$resref} ) { $confref->{$crsHome}{scan}=$resref->{$id}; } return $confref->{$crsHome}{scan}; } if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { for my $id ( keys %{$resref} ) { $confref->{$ch}{scan}=$resref->{$id}; } return $confref->{$ch}{scan} if $confref->{$ch} and $confref->{$ch}{scan}; } } return $resref if $resref and keys %{$resref}; warn "WARN:has::Common::hasGetScanInformation Failed to get Information for Scan resource" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetScanVIPInformation # # DESC # return the scan VIP Information # # ARGUMENTS # crsHome if known # # RETURNS # hash for results #------------------------------------------------------------------------------ sub hasGetScanVIPInformation(;$) { my ( $crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{scan_vip} if $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{scan_vip}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{scan_vip} if $confref->{$ch} and $confref->{$ch}{scan_vip}; } } if ( not has::Common::hasCheckForEmcrsp($crsHome) ) { warn "WARN:has::Common::hasGetScanInformation:This is a pre 11gR2 cluster, binary emcrsp is not found, no Scan information"; return; } # get the scan information my %meta; $meta{cmd}='emcrsp em config -e resource -p ora.scan_vip.type'; $meta{element_name}='entity'; $meta{entity}{attrs}{entity_name}=1; $meta{entity}{name_value}{NAME}=1; $meta{entity}{name_value}{ID}=1; $meta{entity}{name_value}{USR_ORA_VIP}=1; $meta{entity}{name_value}{TYPE}=1; $meta{entity}{name_value}{BASE_TYPE}=1; $meta{entity}{name_value}{HOSTING_MEMBERS}=1; $meta{entity}{name_value}{LAST_SERVER}=1; $meta{entity}{name_value}{VERSION}=1; my $resref; $resref = has::Common::hasGetEntityInformation(\%meta,$crsHome); # if we have eons data then farm the fields to make sure we have reqd data if ( keys %{$resref} ) { for my $id ( keys %{$resref} ) { $resref->{$id}{SCAN_IP} = $resref->{$id}{USR_ORA_VIP} if defined $resref->{$id}{USR_ORA_VIP}; $resref->{$id}{SCAN_IP}='scanIP_TBD' unless $resref->{$id} and $resref->{$id}{SCAN_IP}; warn "WARN:has::Common::hasGetScanVIPInformation Failed to get SCAN IP for scan VIP resource" unless $resref->{$id} and $resref->{$id}{SCAN_IP}; } } else { warn "WARN:has::Common::hasGetScanVIPInformation Failed to get information for scan vip resource"; $resref->{NO_ID}{SCAN_IP}='scanIP_TBD'; } if ( $crsHome ) { for my $id ( keys %{$resref} ) { $confref->{$crsHome}{scan_vip}=$resref->{$id}; } return $confref->{$crsHome}{scan_vip}; } if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { for my $id ( keys %{$resref} ) { $confref->{$ch}{scan_vip}=$resref->{$id}; } return $confref->{$ch}{scan_vip} if $confref->{$ch} and $confref->{$ch}{scan_vip}; } } return $resref if $resref and keys %{$resref}; warn "WARN:has::Common::hasGetScanVIPInformation Failed to get Information for Scan VIP resource" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetScanPort # # DESC # return the scanPort # # ARGUMENTS # crsHome if known # # RETURNS # scanPort #------------------------------------------------------------------------------ sub hasGetScanPort(;$) { my ( $crsHome ) = @_; my $ref; $ref = has::Common::hasGetScanInformation($crsHome); return $ref->{SCAN_PORT} if defined $ref->{SCAN_PORT}; warn "WARN:has::Common::hasGetScanPort Failed to get Scan Port" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetScanName # # DESC # return the scanName # # ARGUMENTS # crsHome if known # # RETURNS # scanPort #------------------------------------------------------------------------------ sub hasGetScanName(;$) { my ( $crsHome ) = @_; my $ref; $ref = has::Common::hasGetScanInformation($crsHome); return $ref->{SCAN_NAME} if defined $ref->{SCAN_NAME}; warn "WARN:has::Common::hasGetScanPort Failed to get Scan Name" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetScanIP # # DESC # return the scan IP Addres # # ARGUMENTS # crsHome if known # # RETURNS # scanPort #------------------------------------------------------------------------------ sub hasGetScanIP(;$) { my ( $crsHome ) = @_; my $ref; $ref = has::Common::hasGetScanVIPInformation($crsHome); return $ref->{SCAN_IP} if defined $ref->{SCAN_IP}; warn "WARN:has::Common::hasGetScanPort Failed to get Scan IP" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetEONSInformation # # DESC # return the eONS Information # # ARGUMENTS # crsHome if known # # RETURNS # has to be returned #------------------------------------------------------------------------------ sub hasGetEONSInformation(;$) { my ( $crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{eons} if $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{eons}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{eons} if $confref->{$ch} and $confref->{$ch}{eons}; } } if ( not has::Common::hasCheckForEmcrsp($crsHome) ) { warn "WARN:has::Common::hasGetEONSInformation:This is a pre 11gR2 cluster, binary emcrsp is not found, no eons information"; return; } # get the eons information my %meta; $meta{cmd}='emcrsp em config -e resource_instance -p ora\.eons\.type'; $meta{element_name}='entity'; $meta{entity}{attrs}{entity_name}=1; $meta{entity}{name_value}{NAME}=1; $meta{entity}{name_value}{ID}=1; $meta{entity}{name_value}{LAST_SERVER}=1; $meta{entity}{name_value}{PORT}=1; $meta{entity}{name_value}{TYPE}=1; $meta{entity}{name_value}{BASE_TYPE}=1; $meta{entity}{name_value}{HOSTING_MEMBERS}=1; my $resref; $resref = has::Common::hasGetEntityInformation(\%meta,$crsHome); # if we have eons data then farm the fields to make sure we have reqd data if ( keys %{$resref} ) { for my $id ( keys %{$resref} ) { $resref->{$id}{ID} = $resref->{$id}{entity_name} if not $resref->{$id}{ID} and $resref->{entity_name}; # split id of form 'ora.eons stbdq16 1 my $name; my $node; my $instance; ($name,$node, $instance) = ( $resref->{$id}{ID} =~ /^([^\s]+)\s+([^\s]+)\s+([^\s]*)/) if $resref->{$id}{ID} and $resref->{$id}{ID} =~ /^[^\s]+\s+[^\s]+\s+[^\s]*/; $resref->{$id}{NAME} = $name if $name and not $resref->{$id}{NAME}; $resref->{$id}{NAME} = $resref->{$id}{ID} if $resref->{$id}{ID} and not $resref->{$id}{NAME}; $resref->{$id}{NAME} = 'ora\.eons UNKNOWN' unless $resref->{$id}{NAME}; $resref->{$id}{EONS_PORT} = $resref->{$id}{PORT} if defined $resref->{$id}{PORT}; $resref->{$id}{EONS_PORT} = 0 unless defined $resref->{$id}{EONS_PORT}; $resref->{$id}{NODE_NAME} = $resref->{$id}{LAST_SERVER} if $resref->{$id}{LAST_SERVER}; $resref->{$id}{NODE_NAME} = $node if $node and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = "$resref->{$id}{NAME} $instance" if $resref->{$id}{NAME} and $instance and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = $resref->{$id}{ID} if $resref->{$id}{ID} and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = $resref->{$id}{HOSTING_MEMBERS} if $resref->{$id}{HOSTING_MEMBERS} and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = "UNKNOWN $instance" if $instance and not $resref->{$id}{NODE_NAME}; warn "WARN:has::Common::hasGetEONSInformation Failed to get NODE_NAME for eons resource" unless $resref->{$id}{NODE_NAME}; warn "WARN:has::Common::hasGetEONSInformation Failed to get NAME for eons resource" unless $resref->{$id}{NAME}; } if ( $crsHome ) { $confref->{$crsHome}{eons}=$resref; return $confref->{$crsHome}{eons}; } if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { $confref->{$ch}{eons}=$resref; return $confref->{$ch}{eons} if $confref->{$ch} and $confref->{$ch}{eons}; } } } return $resref if $resref and keys %{$resref}; warn "WARN:has::Common::hasGetEONSInformation Failed to get eONS Information" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetEONSPort # # DESC # return the eONS Port # # ARGUMENTS # crsHome if known # # RETURNS # eons port to be returned #------------------------------------------------------------------------------ sub hasGetEONSPort(;$) { my ( $crsHome ) = @_; my $eonsref = has::Common::hasGetEONSInformation($crsHome); my $eonsPort; if ( $eonsref and ref($eonsref) ) { for my $id ( keys %{$eonsref} ) { $eonsPort = $eonsref->{$id}{EONS_PORT} if $eonsref->{$id}{EONS_PORT}; $eonsPort = 0 unless $eonsPort; } } return $eonsPort if defined $eonsPort; warn "WARN:has::Common::hasGetEONSPort Failed to get eONS port" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetVIPInformation # # DESC # return the VIP Information # # ARGUMENTS # crsHome if known # # RETURNS # has to be returned # #------------------------------------------------------------------------------ sub hasGetVIPInformation(;$) { my ( $crsHome ) = @_; my $resref; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{vip} if $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{vip}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{vip} if $confref->{$ch} and $confref->{$ch}{vip}; } } if ( not has::Common::hasCheckForEmcrsp($crsHome) ) { warn "WARN:has::Common::hasGetVIPInformation:This is a pre 11gR2 cluster, binary emcrsp is not found"; return ; } # get the vip information my %meta; $meta{cmd}='emcrsp em config -e resource -p ora\.cluster_vip_net1\.type'; $meta{element_name}='entity'; $meta{entity}{attrs}{entity_name}=1; $meta{entity}{name_value}{NAME}=1; $meta{entity}{name_value}{ID}=1; $meta{entity}{name_value}{LAST_SERVER}=1; $meta{entity}{name_value}{HOSTING_MEMBERS}=1; $meta{entity}{name_value}{USR_ORA_VIP}=1; $meta{entity}{name_value}{TYPE}=1; $meta{entity}{name_value}{BASE_TYPE}=1; $meta{entity}{name_value}{HOSTING_MEMBERS}=1; $resref = has::Common::hasGetEntityInformation(\%meta,$crsHome); # if we have eons data then farm the fields to make sure we have reqd data if ( keys %{$resref} ) { for my $id ( keys %{$resref} ) { $resref->{$id}{ID} = $resref->{$id}{entity_name} if not $resref->{$id}{ID} and $resref->{entity_name}; # split id of form 'ora.stbdq16.vip 1 1 12 my $node; my $name; my $instance; ($name, $instance) = ( $resref->{$id}{ID} =~ /^([^\s]+)\s+([^\s]+)/) if $resref->{$id}{ID} and $resref->{$id}{ID} =~ /^[^\s]+\s+[^\s]+/; $resref->{$id}{NAME} = $name if not $resref->{$id}{NAME} and $name; $resref->{$id}{NAME} = $resref->{$id}{ID} if $resref->{$id}{ID} and not $resref->{$id}{NAME}; $resref->{$id}{NAME} = 'ora\.cluster_vip UNKNOWN' unless $resref->{$id}{NAME}; $resref->{$id}{VIP_IP} = $resref->{$id}{USR_ORA_VIP} if defined $resref->{$id}{USR_ORA_VIP}; $resref->{$id}{VIP_IP} = 0 unless defined $resref->{$id}{VIP_IP}; ($node) = ( $name =~ /ora\.([^'\.vip']+)\.vip/) if $name and $name =~ /ora\..+\.vip/; $resref->{$id}{NODE_NAME} = $resref->{$id}{LAST_SERVER} if $resref->{$id}{LAST_SERVER}; $resref->{$id}{NODE_NAME} = $resref->{$id}{HOSTING_MEMBERS} if $resref->{$id}{HOSTING_MEMBERS} and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = $node if $node and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = "$resref->{$id}{NAME} $instance" if $resref->{$id}{NAME} and $instance and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = $resref->{$id}{ID} if $resref->{$id}{ID} and not $resref->{$id}{NODE_NAME}; $resref->{$id}{NODE_NAME} = "UNKNOWN $instance" if $instance and not $resref->{$id}{NODE_NAME}; warn "WARN:has::Common::hasGetVIPInformation Failed to get NODE_NAME for vip resource" unless $resref->{$id}{NODE_NAME}; warn "WARN:has::Common::hasGetVIPInformation Failed to get NAME for vip resource" unless $resref->{$id}{NAME}; warn "WARN:has::Common::hasGetVIPInformation Failed to get IP Address for vip resource" unless $resref->{$id}{VIP_IP}; } if ( $crsHome ) { $confref->{$crsHome}{vip}=$resref; return $confref->{$crsHome}{vip}; } if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { $confref->{$ch}{vip}=$resref; return $confref->{$ch}{vip} if $confref->{$ch} and $confref->{$ch}{vip}; } } } return $resref if $resref and keys %{$resref}; warn "WARN:has::Common::hasGetVIPInformation Failed to get VIP Information" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetVotingDiskInformation # # DESC # return the Voting Disk Information # # ARGUMENTS # crsHome if known # # RETURNS # hash for results #------------------------------------------------------------------------------ sub hasGetVotingDiskInformation(;$) { my ( $crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{votingdisk} if $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{votingdisk}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{votingdisk} if $confref->{$ch} and $confref->{$ch}{votingdisk}; } } # get the scan information my %results; $results{'voting_disk_location_tbd'}{LOCATION}='voting_disk_location_tbd'; return \%results; warn "WARN:has::Common::hasGetVotingDiskInformation Failed to get Voting Disk Information " and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetOCRInformation # # DESC # return the OCR Information # # ARGUMENTS # crsHome if known # # RETURNS # hash for results #------------------------------------------------------------------------------ sub hasGetOCRInformation(;$) { my ( $crsHome ) = @_; my $confref = has::Common::getClusterCacheRef(); return $confref->{$crsHome}{OCR} if $crsHome and $confref and ref($confref) and keys %{$confref} and $confref->{$crsHome} and $confref->{$crsHome}{OCR}; if ( $confref and ref($confref) and keys %{$confref} ) { for my $ch ( keys %{$confref} ) { return $confref->{$ch}{OCR} if $confref->{$ch} and $confref->{$ch}{OCR}; } } # get the scan information my %results; $results{'ocr_location_tbd'}{LOCATION}='ocr_location_tbd'; $results{'ocr_location_tbd'}{MIRRORS}=1; return \%results; warn "WARN:has::Common::hasGetOCRInformation Failed to get Voting Disk Information " and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetSQLResults # # DESC # return FALSE or HAS Name # # ARGUMENTS # ref to hash of credentials # $credentialsRef = # { # username =>'system', # password => 'manmager', # address => '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<dbhostname>)(Port=<port>))(CONNECT_DATA=(SID=<sid>)))', # role => SYSDBA|SYSOPER, # oracle_home => '/u01/oracle' # sql => # [ ( sql1, sql2) ] # # a list of sqls to execute # DB connection timeout and retry values in secs, optional # db_timeout => 10; #timeout secs # db_retry => 3; #number of retries # db_waittime => 60; #wait time before retry # }; # # ref to hash with result field order details by sql # $orderOfFieldsRef = { sql1 => { 'col1' =>1 , 'col2' =>2 } # sql2 => { 'col1' =>1 , 'col2' =>2 } } ; # this arg is optional. If this arg is passed then results are returned with each result row as hash # without this arg each row is returned as a list # # RETURNS # an ref to an has by sql # each value for a sql gives the result list for that sql # where each element in the list is a ref to the result row # the result row is either a has if orderOfFieldsRef is passed else a list #------------------------------------------------------------------------------ #sub hasGetSQLResults($;$) #{ # my ( $credentialsRef,$orderOfFieldsRef ) = @_; # return has::SQL::hasGetSQLResults($credentialsRef,$orderOfFieldsRef); #} #------------------------------------------------------------------------------ # FUNCTION : hasGetDBResourceInformation # # DESC # use emcrsp to get resource informatrion for a single instance db # # ARGUMENTS # crsHome # # RETURNS # hash for database attributes by database resource name #------------------------------------------------------------------------------ sub hasGetDBResourceInformation($) { my ( $crsHome ) = @_; if ( not has::Common::hasCheckForEmcrsp($crsHome) ) { warn "WARN:has::Common::hasGetDBResourceInformation:This is a pre 11gR2 cluster, binary emcrsp is not found, no Scan information"; return; } # get the db target type information my %meta; $meta{cmd}='emcrsp em config -e resource -p ora.database.type'; $meta{element_name}='entity'; $meta{entity}{attrs}{entity_name}=1; $meta{entity}{name_value}{USR_ORA_DB_UNIQUE_NAME}=1; $meta{entity}{name_value}{USR_ORA_INST_NAME}=1; $meta{entity}{name_value}{NAME}=1; $meta{entity}{name_value}{ORACLE_HOME}=1; my $resref; $resref = has::Common::hasGetEntityInformation(\%meta,$crsHome); return $resref if $resref and keys %{$resref}; warn "WARN:has::Common::hasGetDBResourceInformation Failed to get database resource information from crs $crsHome" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasGetLsnrResourceInformation # # DESC # use emcrsp to get resource informatrion for a single instance listener # # ARGUMENTS # crsHome # # RETURNS # hash for listener attributes by listener resource name #------------------------------------------------------------------------------ sub hasGetLsnrResourceInformation($) { my ( $crsHome ) = @_; if ( not has::Common::hasCheckForEmcrsp($crsHome) ) { warn "WARN:has::Common::hasGetLsnrResourceInformation:This is a pre 11gR2 cluster, binary emcrsp is not found, no Scan information"; return; } # get the lsnr target type information my %meta; $meta{cmd}='emcrsp em config -e resource -p ora.listener.type'; $meta{element_name}='entity'; $meta{entity}{attrs}{entity_name}=1; $meta{entity}{name_value}{PORT}=1; my $resref; $resref = has::Common::hasGetEntityInformation(\%meta,$crsHome); return $resref if $resref and keys %{$resref}; warn "WARN:has::Common::hasGetLsnrResourceInformation Failed to get database resource information from crs $crsHome" and return; } #------------------------------------------------------------------------------ # FUNCTION : hasIsDBManagedByHas # # DESC # return FALSE or HAS Name # # ARGUMENTS # username # password # connect string # role # dbOracleHome # dbVersion - this helps in choosing the righ sql if sqls are versioned # # RETURNS # return FALSE or HAS Name #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # FUNCTION : hasIsDBManagedByHas # # DESC # return FALSE or HAS Name # # ARGUMENTS # username # password # connect string # role # dbOracleHome # sid # dbVersion - this helps in choosing the righ sql if sqls are versioned # # RETURNS # return FALSE or HAS Name #------------------------------------------------------------------------------ sub hasIsDBManagedByHas($$$$;$$$) { my ( $username,$password,$address,$role,$dbOracleHome,$sid,$dbVersion ) = @_; my $dynProp = 'TRUE'; # define the other configuration variables my $sql= " SELECT \'YES\'\"has_db\" FROM v\$session vs /*+ all_rows use_concat */ WHERE (vs.client_info = \'oraagent\') AND ROWNUM = 1"; my $sql_par = "SELECT parallel \"parallel\" FROM v\$instance"; my $dbsql = " SELECT database_name \"db_name\" FROM ( SELECT name, value database_name FROM v\$parameter WHERE (name = \'db_unique_name\' OR name = \'db_name\') AND value IS NOT NULL ORDER BY name DESC ) WHERE ROWNUM = 1"; # order of fields in the results my %fieldOrder; $fieldOrder{$sql} = {has_db=>1 }; $fieldOrder{$sql_par} = {parallel=>1 }; $fieldOrder{$dbsql} = { db_name =>1 }; # pupulate the credentials array my %credentials; $credentials{username} = $username if $username; $credentials{password} = $password if $password; $credentials{address} = $address if $address; $credentials{role} = $role if $role; $credentials{sql} = [ ( $sql,$sql_par,$dbsql ) ]; #----------------------------------------------------------------------------------------- # subs declared my $hasDB = 'NO'; my $parallel = 'NO'; my $ocrType = 'cluster'; my $clusterOcr = 1; my $hasManaged = 'N/A'; my $oracleName = $ENV{EM_ORACLE_SID} if $ENV{EM_ORACLE_SID}; # if the verson category is less than 11gR2 then db cannot be HA managed if ( keys %ENV and $ENV{EM_VERSION_CATEGORY} and $ENV{EM_VERSION_CATEGORY} =~ /^(pre8|8i|8iR2|9i|9iR2|10gR1|10gR2|10gR203|11gR1)$/ ) { return wantarray? ($hasManaged,undef):$hasManaged; } my $results_ref = has::Common::hasGetSQLResults(\%credentials,\%fieldOrder); my $array_ref; if ( $results_ref and keys %{$results_ref} ) { for my $sq ( keys %{$results_ref} ) { # check if db is had managed $array_ref = $results_ref->{$sq}; if ( $array_ref and ref($array_ref) and ref($array_ref) =~ /LIST|ARRAY/ and @{$array_ref} ) { # parse query results to check if db has has for my $row ( @{$array_ref} ) { my %rowhash = %{$row}; $hasDB = $rowhash{has_db} if $rowhash{has_db}; $parallel = $rowhash{parallel} if $rowhash{parallel}; $oracleName = $rowhash{db_name} if $rowhash{db_name}; #last if $hasDB and $parallel; } } } } # cluster database is not has managed if ( $parallel and $parallel =~ /YES/i ) { $hasManaged = 'N/A'; return wantarray? ($hasManaged,undef):$hasManaged; } # if not single instance has managed database # check if it has a resource name my $resourceName = undef; if ( not $hasDB or $hasDB !~ /^YES$/i ) { $resourceName = has::Common::hasGetResourceNameForOracleApp($dbOracleHome,'database',$oracleName); } my $cHome = undef; my $HasManagedCRSHome = undef; # failed to get from db try to find a crs home and get information my $discResultsref = has::Common::hasDiscoverCluster($dynProp); if ( $discResultsref and keys %{$discResultsref} ) { for my $crsHome ( keys %{$discResultsref} ) { # code below this will not execute on nt as emcrsp is not in the nt shiphome for beta1 if ( has::Common::hasCheckForEmcrsp($crsHome) ) { $cHome = $crsHome; $ocrType = has::Common::hasGetOcrType($crsHome,$dynProp); # there is a single instance ha on the box but the db table shows none if ( $ocrType and $ocrType =~ /has/i ) { $HasManagedCRSHome = $crsHome; my $db_ref = has::Common::hasGetDBResourceInformation($crsHome); if ( $db_ref and keys %{$db_ref} ) { for my $dbres ( keys %{$db_ref} ) { if ( $db_ref->{$dbres} ) { if ( $dbOracleHome and $sid and $db_ref->{$dbres}{ORACLE_HOME} and $db_ref->{$dbres}{ORACLE_HOME} eq $dbOracleHome and $db_ref->{$dbres}{USR_ORA_INST_NAME} and $db_ref->{$dbres}{USR_ORA_INST_NAME} =~ /^$sid$/ ) { $hasManaged = "YES"; return wantarray? ($hasManaged,$HasManagedCRSHome):$hasManaged; } elsif ( $resourceName and $db_ref->{$dbres}{NAME} and $db_ref->{$dbres} =~ /^$resourceName$/ ) { $hasManaged = "YES"; return wantarray? ($hasManaged,$HasManagedCRSHome):$hasManaged; } } } } } elsif ( $ocrType and $ocrType =~ /cluster/ ) { $clusterOcr = 1; } } } } # there is a single instance HAS if ( $HasManagedCRSHome ) { $cHome = $HasManagedCRSHome; if ( $resourceName ) { $hasManaged = 'YES'; } elsif ( $hasDB and $hasDB =~ /^YES$/i ) { $hasManaged = 'YES'; } else { $hasManaged = 'NO'; } } else { $cHome = undef; if ( $resourceName ) { $hasManaged = 'N/A'; warn "WARN:has::Common::hasIsDBManagedByHas: No HA install found \n" unless $clusterOcr; } elsif ( $hasDB and $hasDB =~ /^YES$/i ) { $hasManaged = 'N/A'; warn "WARN:has::Common::hasIsDBManagedByHas: No HA install found \n"; } else { $hasManaged = 'N/A'; } } return wantarray? ($hasManaged,$cHome):$hasManaged; } #sub hasIsDBManagedByHas($$$$;$$) #{ # # my ( $username,$password,$address,$role,$dbOracleHome,$dbVersion ) = @_; # # # # define the other configuration variables # my $sql= # " # SELECT \'TRUE\'\"has_db\" # FROM v\$session vs /*+ all_rows use_concat */ # WHERE (vs.client_info = \'oraagent\') # AND ROWNUM = 1"; # # # order of fields in the results # my %fieldOrder; # $fieldOrder{$sql} = {has_db=>1 }; # # # pupulate the credentials array # my %credentials; # $credentials{username} = $username if $username; # $credentials{password} = $password if $password; # $credentials{address} = $address if $address; # $credentials{role} = $role if $role; # $credentials{sql} = [ ( $sql ) ]; # # # #----------------------------------------------------------------------------------------- # # subs declared # my $ocrType = 'FALSE'; # # my $results_ref = has::Common::hasGetSQLResults(\%credentials,\%fieldOrder); # # my $array_ref; # # $array_ref = $results_ref->{$sql} if $results_ref and keys %{$results_ref} and $results_ref->{$sql}; # # if ( $array_ref and ref($array_ref) and ref($array_ref) =~ /LIST/ and @{$array_ref} ) # { # # parse query results to check if db has has # for my $row ( @{$array_ref} ) # { # my %rowhash = %{$row}; # # $ocrType = $rowhash{has_db} if $rowhash{has_db}; # # last if $ocrType; # } # } # else # { # # failed to get from db try to find a crs home and get information # my $discResultsref = has::Common::hasDiscoverCluster(); # # if ( $discResultsref and keys %{$discResultsref} ) # { # # for my $crsHome ( keys %{$discResultsref} ) # { # # $ocrType = has::Common::hasGetOcrType($crsHome); # # if ( $ocrType and $ocrType =~ /has/i ) # { # # $ocrType ='TRUE'; # # return wantarray? ($ocrType,$crsHome):$ocrType; # # } # # } # } # } # # return wantarray? ($ocrType,undef):$ocrType; # #} #------------------------------------------------------------------------------ # FUNCTION : hasIsLsnrManagedByHas # # DESC # return FALSE or HAS Name # # ARGUMENTS # oracle Home # Listener Port # listner name ( optional) # # RETURNS # return FALSE or HAS Name #------------------------------------------------------------------------------ sub hasIsLsnrManagedByHas($$;$) { my ( $oracleHome,$lsnrPort,$oracleName ) = @_; my $dynProp = 'TRUE'; my $ocrType = 'cluster'; my $clusterOcr = 1; my $hasManaged = 'N/A'; my $cHome = undef; my $HasManagedCRSHome = undef; # if not single instance has managed database # check if it has a resource name my ($resourceName,$isScan) = has::Common::hasGetResourceNameForOracleApp($oracleHome,'listener',$oracleName,$lsnrPort); # scan listener is not has managed if ( $isScan and $isScan =~ /TRUE/ ) { return wantarray? ($hasManaged,$cHome):$hasManaged; } # failed to get from db try to find a crs home and get information my $discResultsref = has::Common::hasDiscoverCluster($dynProp); if ( $discResultsref and keys %{$discResultsref} ) { for my $crsHome ( keys %{$discResultsref} ) { # code below this will not execute on nt as emcrsp is not in the nt shiphome for beta1 if ( has::Common::hasCheckForEmcrsp($crsHome) ) { $cHome = $crsHome; $ocrType = has::Common::hasGetOcrType($crsHome,$dynProp); # there is a single instance ha on the box but the db table shows none if ( $ocrType and $ocrType =~ /has/i ) { $HasManagedCRSHome = $crsHome; my $db_ref = has::Common::hasGetLsnrResourceInformation($crsHome); if ( $db_ref and keys %{$db_ref} ) { for my $dbres ( keys %{$db_ref} ) { if ( $db_ref->{$dbres} ) { if ( $db_ref->{$dbres}{PORT} and $db_ref->{$dbres}{PORT} =~ /^$lsnrPort$/ ) { $hasManaged = "YES"; return wantarray? ($hasManaged,$HasManagedCRSHome):$hasManaged; } elsif ( $resourceName and $db_ref->{$dbres}{NAME} and $db_ref->{$dbres} =~ /^$resourceName$/ ) { $hasManaged = "YES"; return wantarray? ($hasManaged,$HasManagedCRSHome):$hasManaged; } } } } } elsif ( $ocrType and $ocrType =~ /cluster/ ) { $clusterOcr = 1; } } } } # there is a single instance HAS if ( $HasManagedCRSHome ) { $cHome = $HasManagedCRSHome; if ( $resourceName ) { $hasManaged = 'YES'; } else { $hasManaged = 'NO'; } } else { $cHome = undef; if ( $resourceName ) { $hasManaged = 'N/A'; warn "WARN:has::Common::hasIsDBManagedByHas: No HA install found \n" unless $clusterOcr; } else { $hasManaged = 'N/A'; } } return wantarray? ($hasManaged,$cHome):$hasManaged; } #------------------------------------------------------------------------------ # FUNCTION : hasCheckAndReturnEmcrspResults # # DESC: # checks he command results to make sure they do not have anything # other than the stdout printed from emcrsp # # arg : # cmdresults from emcrsp # # return: # return the ckecked cmd results #------------------------------------------------------------------------------ sub hasCheckAndReturnEmcrspResults($) { my ( $cmdresults ) = @_; my @ress = split/\n/,$cmdresults if $cmdresults; my $temp_res; for my $resss ( @ress ) { next unless $resss and $resss =~ /^\s*</; $temp_res = '' unless $temp_res; $temp_res = "$temp_res$resss\n"; } return $temp_res if $temp_res; return; } #------------------------------------------------------------------------------ # FUNCTION : hasadm_resource_types_mark_base_types # # DESC # this function will mark the base type, # build the base_type_chain # mark the base resource type for each attribute of a resource type # # arg : # ref to hash list of resource types with attribs parsed from xml # # return: #------------------------------------------------------------------------------ sub hasadm_resource_types_mark_base_types($) { # name : hasadm_resourcetype_markbase_fn # desc : for each resource type element passed it keeps track of the base type # # arg : # ref to xml element to be filtered #``ref to the result hass entities array # sub hasadm_resourcetype_markbase_fn($$) { my ( $elref, $rsref ) = @_; return 1 unless $elref->{element} and $elref->{element} =~ /^(entity|attribute)$/i; # keep an index of resource_type to base_type if ( $elref->{element} =~ /^attribute$/i ) { # attribute should have the name ,value .. child elements return 1 unless $elref->{children}; my $entity_ref; #get the resource_type entity $entity_ref = $elref->{parent}->{parent} if $elref->{parent} and $elref->{parent}->{parent}; return 1 unless $entity_ref and $entity_ref->{attrs} and $entity_ref->{attrs}{entity_name}; return 1 unless $entity_ref->{attrs}{entity_type} and $entity_ref->{attrs}{entity_type} =~ /^resource_type$/i; # get the default_value for name= BASE_TYPE my $val = ''; my $name; for my $elem ( @{$elref->{children}} ) { next unless $elem and $elem->{element} and $elem->{element} =~ /^(name|default_value)$/i; $name = $elem->{name} and next if $elem->{element} =~ /name/ and $elem->{name}; $val = $elem->{name} and next if $elem->{element} =~ /default_value/ and $elem->{name}; } return 1 unless $name; #keep an look up list of resource attrib and default value #this is for marking as to the resource type a attrib comes from $has::Common::hasadm_restype_attrib{$entity_ref->{attrs}{entity_name}}{$name}=$val if $val; $has::Common::hasadm_restype_attrib{$entity_ref->{attrs}{entity_name}}{$name}='' unless $val; return 1 unless $name and $name =~ /^BASE_TYPE$/i; $has::Common::hasadm_restype_base{$entity_ref->{attrs}{entity_name}}{base_type}= $val; return 1; } return 1 unless $elref->{attrs} and $elref->{attrs}{entity_type} and $elref->{attrs}{entity_type} =~ /^resource_type$/i; #has::Common::append_element($rsref,$elref); # keep an has stack of resource types return 1 unless $elref->{attrs}{entity_name}; $has::Common::hasadm_resource_type_list{$elref->{attrs}{entity_name}}=$elref; return 1; } # name : hasadm_resource_attrib_type_fn # desc : for each attrib passed it gets the source resource type for that attrib # # arg : # ref to xml element to be filtered #``ref to the result hass entities array # sub hasadm_resource_attrib_type_fn($$) { my ( $elref, $rsref ) = @_; return 1 unless $elref->{element} and $elref->{element} =~ /^(entity)$/i; return 1 unless $elref->{attrs} and $elref->{attrs}{entity_type} and $elref->{attrs}{entity_type} =~ /^resource_type$/i; return 1 unless $elref->{attrs}{entity_name}; my $base_type_chain; my @base_types; $base_type_chain = $elref->{attrs}{base_type_chain} if $elref->{attrs}{base_type_chain}; @base_types = split/,/,$base_type_chain if $base_type_chain; # go thru each attrib and get the name and go thru base_type_chain to get the root resource type # for that attrib name for my $attribs ( @{$elref->{children}} ) { for my $attrib ( @{$attribs->{children}} ) { for my $elem ( @{$attrib->{children}} ) { next unless $elem and $elem->{element} and $elem->{element} =~ /^(name)$/i; my $name; $name = $elem->{name} if $elem->{element} =~ /name/ and $elem->{name}; $name =~ s/^\s+|\s+$//g if $name; next unless $name; # for each attrib get the base name from where it came # move from the leaf to the root, so the root for attrib sticks my $attribResType; my $attribResValue; for my $btype ( @base_types ) { $btype =~ s/^\s+|\s+$//g if $btype; next unless $btype; next unless $has::Common::hasadm_restype_attrib{$btype} and defined $has::Common::hasadm_restype_attrib{$btype}{$name}; $attribResType = $btype; $attribResValue = $has::Common::hasadm_restype_attrib{$btype}{$name} if $has::Common::hasadm_restype_attrib{$btype}{$name}; } if ( not $attribResType ) { $attribResType = $elref->{attrs}{entity_name}; $attribResValue = $has::Common::hasadm_restype_attrib{$elref->{attrs}{entity_name}}{$name} if $has::Common::hasadm_restype_attrib{$elref->{attrs}{entity_name}} and $has::Common::hasadm_restype_attrib{$elref->{attrs}{entity_name}}{$name}; } $attribResType = '' unless $attribResType; $attribResValue = '' unless $attribResValue; my %attribResElement; my %attribResValueElement; my $attribResElementRef = has::Common::make_element('resource_type',$attribResType); my $attribResValueElementRef = has::Common::make_element('base_attrib_value',$attribResValue); has::Common::append_element($attrib,$attribResElementRef); has::Common::append_element($attrib,$attribResValueElementRef); last; } } } return 1; } my ( $reslistref ) = @_; %has::Common::hasadm_restype_base = (); %has::Common::hasadm_resource_type_list = (); has::Common::traverse_xml($reslistref,\&has::Common::has_handle_error,\&hasadm_resourcetype_markbase_fn,$reslistref); # create the coma separated string list of resource types if ( keys %has::Common::hasadm_restype_base ) { # for each resource type build the stack for my $res ( keys %has::Common::hasadm_restype_base ) { next if $has::Common::hasadm_restype_base{$res}{chain}; my @bstack; my $bres = $res; while ( $bres ) { # build a stack of base resource types push @bstack,$bres; $bres = $has::Common::hasadm_restype_base{$bres}{base_type}; if ( not $bres ) { # reached the base resource type, start building the chain my $chain=''; my $pres = pop @bstack; while ( $pres ) { $has::Common::hasadm_restype_base{$pres}{base_type_chain}=$chain unless $has::Common::hasadm_restype_base{$pres}{base_type_chain}; $chain = "$pres,$chain" if $chain; $chain = $pres unless $chain; $pres = pop @bstack; } } } } } # get the resource type chain for each resource for my $restype ( keys %has::Common::hasadm_resource_type_list ) { my $resref = $has::Common::hasadm_resource_type_list{$restype}; $resref->{attrs}{root_type} = ''; $resref->{attrs}{base_type_chain} = ''; $resref->{attrs}{root_type}=$has::Common::hasadm_restype_base{$restype}{base_type} if $has::Common::hasadm_restype_base{$restype}{base_type}; $resref->{attrs}{base_type_chain}=$has::Common::hasadm_restype_base{$restype}{base_type_chain} if $has::Common::hasadm_restype_base{$restype}{base_type_chain}; } # for each resource type go up the base chain and mark the source resource type for each attrib has::Common::traverse_xml($reslistref,\&has::Common::has_handle_error,\&hasadm_resource_attrib_type_fn,$reslistref); return 1; } # name : hasGetResourceNameForOracleApp # desc : return the resource name for oracle type, oracle name # # arg : # oracleHome of the resource # type of resource (database,listener,service,scanlistener,asm,eons) # oracle name of the reesource # # return: # sub hasGetResourceNameForOracleApp($$;$$) { my ($oracleHome,$oracleType,$oracleName,$oracleName2 ) = @_; my $resName = undef; my $type1; my $type2; my $nown; my $isScan = undef; warn "ERROR:has::Common::hasGetResourceNameForOracleApp, ORACLE Home not passed for getting resource name\n" and return unless $oracleHome; warn "ERROR:has::Common::hasGetResourceNameForOracleApp , Type not passed for getting resource name\n" and return unless $oracleType; # if listener check if there is a scan listener if ( $oracleType =~ /^(listener|oracle_listener|scan_listener)$/ ) { my $scanRef = has::Common::hasGetScanInformation(); if ( $scanRef and ref($scanRef) and ref($scanRef) =~ /HASH/i and keys %{$scanRef} ) { if ( $scanRef->{SCAN_PORT} and $scanRef->{SCAN_PORT} =~ /^$oracleName2$/ ) { $isScan = 'TRUE'; $oracleType = 'scan_listener'; $resName = $scanRef->{SCAN_NAME} if $scanRef->{SCAN_NAME}; return wantarray? ($resName,$isScan):$resName if $resName; last; } } } if ( $oracleType =~ /database|oracle_database|rac_database/ ) { $type1 = 'dbunique_name'; $nown = 'database'; } elsif ( $oracleType =~ /listener|oracle_listener/ ) { $type1 = 'ports'; $nown = 'listener'; } elsif ( $oracleType =~ /asm|asm_instance/ ) { $type1 = 'asm_name'; $nown = 'asm'; } elsif ( $oracleType =~ /scan_listener/ ) { $isScan = 'TRUE'; $type1 = 'port'; $type2 = 'lsnr_name'; $nown = 'scan_listener'; } else { warn "ERROR:has::Common::hasGetResourceNameForOracleApp unsupported type $oracleType, for getting resource name\n"; return; } # set oracle home # execute srvctl config <> -S 1 # if run is successful parse for # unset oracle home # for oracle internal resources we do not want to throw an error if the srvctl command is not supported # for older versions, so check for srvctl and throw and debug message if ( $oracleHome ) { my $srvctl_full_path; my $obindir = catfile($oracleHome,'bin'); for my $extn ( ( '', '.exe', '.bat' ) ) { my $tcmd = "srvctl$extn"; $srvctl_full_path = catfile($obindir,$tcmd); last if has::Common::hasIsReadable($srvctl_full_path); undef $srvctl_full_path; next; } warn "DEBUG:has::Common::hasGetResourceNameForOracleApp , resource name is not supported, command srvctl is not presnt in ORACLE HOME $oracleHome\n" and return unless $srvctl_full_path; } has::Common::hasSetCRSEnv($oracleHome); my %command_args = (exit_failure_list => [()]); my $vo; $vo = has::Common::runsystemcommand("srvctl","config $nown -S 1",\%command_args); if ( $command_args{command_return_status} or not $vo ) { if ( $nown =~ /database/ and $oracleName ) { %command_args = (exit_failure_list => [()]); $vo = has::Common::runsystemcommand("srvctl","config $nown -d $oracleName -S 1",\%command_args); } elsif ( $nown =~ /^listener$/ and $oracleName ) { %command_args = (exit_failure_list => [()]); $vo = has::Common::runsystemcommand("srvctl","config $nown -l $oracleName -S 1",\%command_args); } } has::Common::hasRestoreCRSEnv(); warn "DEBUG:has::Common::hasGetResourceNameForOracleApp Error executing srvctl config $nown -S 1" if $command_args{command_return_status}; return wantarray? ($resName,$isScan):$resName if $command_args{command_return_status}; chomp($vo) if $vo; $vo =~ s/^\s+|\s+$// if $vo; my @rows = split /\n/,$vo if $vo; warn "DEBUG:has::Common::hasGetResourceNameForOracleApp Failed to get any output from command srvctl config $nown -S 1" unless @rows; #parse for res_name={resource name} for my $row ( @rows ) { $row =~ s/^\s+|\s+$// if $row; next unless $row =~ /res_name=/; if ( $nown =~ /database|listener|scan_listener/ ) { next unless $row =~ /$type1=/; if ( $nown =~ /database/ and $oracleName ) { next unless $row =~ /$type1={\s*$oracleName\s*}/; } elsif ( $nown =~ /listener|scan_listener/ and $oracleName2 ) { next unless $row =~ /$type1={\s*$oracleName2\s*}/; } } ( $resName ) = ( $row =~ /res_name=\s*{\s*([^}]+)\s*}/ ); last if $resName; } warn "DEBUG:has::Common::hasGetResourceNameForOracleApp Failed to get resource name from command srvctl config $nown -S 1" unless $resName; return wantarray? ($resName,$isScan):$resName; } # name : hasListenerGetScanName # desc : return the scan name for scan listener # # arg : # oracleHome of the listener # name of the listener # # return: # scan name # sub hasListenerGetScanName($;$) { my ($oracleHome,$oracleName ) = @_; # yet to implement the srvctl implementation return has::Common::hasGetScanName(); } # name : hasIsListenerScan # desc : return true if listener is scan, false otherwise # # arg : # oracleHome of the listener # name of the listener # # return: # scan name # sub hasIsListenerScan($;$) { my ($oracleHome,$oracleName ) = @_; # yet to implement the srvctl implementation my $scanname = has::Common::hasGetScanName(); return 1 if $scanname; return 0; } # name : has_dependencies # desc : for each element passed it gets the dependencies and instruments them # # arg : # ref to xml element to be filtered # ref to xml ref to be returned back # metric_name being processed # sub has_dependencies($$$) { my ( $elref, $rsref, $metric_name ) = @_; my $parent_metric_name; # storage an empty value, if there are no custom attribs the metric exec # should not fail $rsref->{$metric_name} = [()] unless $rsref->{$metric_name}; # this is a function for dependent metrics, get the parent metric_name warn "WARN:Failed, parent metric is not defined for dependent metric $metric_name\n" and return unless $has::Common::has_metric_config{parent_metric}{$metric_name}; $parent_metric_name = $has::Common::has_metric_config{parent_metric}{$metric_name}; # this should have already have has the elemm attribs instrumented return 1 unless $elref->{elem_attribs}; # instrument both the start and stop dependencies for my $depStartStop ( sort qw ( START_DEPENDENCIES STOP_DEPENDENCIES ) ) { next unless $elref->{elem_attribs}{$depStartStop}; # get the start or stop dependency string my $depls = $elref->{elem_attribs}{$depStartStop}; $depls =~ s/^\s+|\s+$//g if $depls; next unless $depls; # replace end brace with )== to easily split them $depls =~ s/\)/\)\=\=/g; my @deplist = split/\=\=/,$depls; for my $dps ( @deplist ) { my $pref; chomp $dps; $dps =~ s/^\s+|\s+$//g; next unless $dps; # get the dependency attrib 1 from attrib>(<a>,<b>,..) my ( $dependentAttrib1,$depnds) = ( $dps =~ /^(.+)\((.*)\)$/); $dependentAttrib1 =~ s/^\s+|\s+$//g if $dependentAttrib1; $depnds =~ s/^\s+|\s+$//g if $depnds; warn "WARN:has_metrics.pl::has_dependencies Failed to get dependency type from $dps" and next unless $dependentAttrib1; warn "WARN:has_metrics.pl::has_dependencies Failed to get dependent name list from $dps" and next unless $depnds; # get the list of dependents from , seperated list my @dependentList = split/,/,$depnds; for my $dependents ( @dependentList ) { my $dependentName; my $dependentAttrib2; chomp $dependents; $dependents =~ s/^\s+|\s+$//g; warn "WARN:has_metrics.pl::has_dependencies Got Null for dependents from $depnds" and next unless $dependents; $dependentName = $dependents; # get the second attrib if the dependent name has a : ($dependentAttrib2,$dependentName) = ( $dependentName =~ /(.+):(.*)/) if $dependentName =~ /:/; $pref->{DEPENDENCY_TYPE}=$depStartStop; $pref->{DEPENDENT_NAME}=$dependentName; $pref->{DEPENDENCY_ATTRIB1}=$dependentAttrib1; $pref->{DEPENDENCY_ATTRIB2}=$dependentAttrib2; $pref->{DEPENDENCY_ATTRIB1}='NA' unless $pref->{DEPENDENCY_ATTRIB1}; $pref->{DEPENDENCY_ATTRIB2}='NA' unless $pref->{DEPENDENCY_ATTRIB2}; # get the attrib 1 for the dependency for my $dpat1 ( qw ( hard weak attraction dispersion pullup ) ) { $pref->{uc $dpat1} = 'YES' if $dependentAttrib1 =~ /^$dpat1$/i; $pref->{uc $dpat1} = 'NO' unless $pref->{uc $dpat1}; } # get the attrib 2 for the dependency for my $dpat2 ( qw ( global ) ) { $pref->{uc $dpat2} = 'YES' if $dependentAttrib2 and $dependentAttrib2 =~ /^$dpat2$/i; $pref->{uc $dpat2} = 'NO' unless $pref->{uc $dpat2}; } # build the em_results row has_em_results($elref,$rsref,$metric_name,$pref); } } } return 1; } # name : has_em_results # desc : for each element passed it gets the metric cols # and build the em_result row after verufying the keys # # arg : # ref to xml element to be filtered # ref to xml ref to be returned back # metric_name being processed # ref to attribute element to be printed for dependent metrics # sub has_em_results ($$$;$) { my ($elref,$rsref,$metric_name,$pref) = @_; # build the result string if ( $has::Common::has_metric_config{basic_fields}{$metric_name} ) { my $retstr = 'em_result='; my %hashret; for my $attrpos ( sort { $a <=> $b } keys %{$has::Common::has_metric_config{basic_fields}{$metric_name}} ) { my $attr; my $metval = ''; $attr = $has::Common::has_metric_config{basic_fields}{$metric_name}{$attrpos}; # if the attr starts with # then its an attr element name # this is so as not to confuse things like entity name with attribute NAME if ( $attr =~ /NULLSTRING_/ ) { $metval=''; } elsif ( $attr !~ /^#/ ) { $metval = $elref->{elem_attribs}{$attr} if defined $elref->{elem_attribs}{$attr} ; $metval = $elref->{elem_attribs}{lc $attr} if defined $elref->{elem_attribs}{lc $attr} ; $metval = $elref->{elem_attribs}{uc $attr} if defined $elref->{elem_attribs}{uc $attr} ; } else { my $nattr = $attr; $nattr =~ s/^#//; $metval = $pref->{$nattr} if defined $pref->{$nattr} ; $metval = $pref->{lc $nattr} if defined $pref->{lc $nattr} ; $metval = $pref->{uc $nattr} if defined $pref->{uc $nattr} ; } # | is special char for em, repalce it if it is in value $metval =~ s/\|+/_/g; # do this special for _NULL values change them to NULL $metval = 'NULL' if $metval =~ /^_NULL$/; # validate metric value , data type checks if ( $has::Common::has_metric_config{data_type}{$metric_name}{$attr} ) { my $datatype = $has::Common::has_metric_config{data_type}{$metric_name}{$attr}; if ( $datatype =~ /number/i ) { $metval = 0 if $metval =~ /^NULL$/; $metval = 0 unless $metval; $metval = 0 unless defined $metval; warn "WARN:Invalid metric value $metval for metric column $attr for metic $metric_name not a number" and next unless $metval =~ /\d*/; } elsif ( $datatype =~ /boolean/ ) { $metval = 1 if $metval =~ /YES|TRUE/i; $metval = 0 if $metval =~ /NO|FALSE/i; $metval = 0 if $metval =~ /^NULL$/; warn "WARN:Invalid metric value $metval for metric column $attr for metic $metric_name not a boolean" and next unless $metval =~ /\d+/ and ( $metval == 0 or $metval == 1 ); } } $retstr .= "$metval|"; $hashret{$attr} = $metval; } # we might have keys which are not in the list of columns # so pick key values fro them and store them in hashret for my $kno ( keys %{$has::Common::has_metric_config{key_fields}{$metric_name}} ) { for my $keypos ( sort { $a <=>$b } keys %{$has::Common::has_metric_config{key_fields}{$metric_name}{$kno}} ) { my $attr; my $metval = ''; $attr = $has::Common::has_metric_config{key_fields}{$metric_name}{$kno}{$keypos}; next if $hashret{$attr}; # if the attr starts with # then its an attr element name # this is so as not to confuse things like entity name with attribute NAME if ( $attr =~ /NULLSTRING_/ ) { $metval=''; } elsif ( $attr !~ /^#/ ) { $metval = $elref->{elem_attribs}{$attr} if defined $elref->{elem_attribs}{$attr} ; $metval = $elref->{elem_attribs}{lc $attr} if defined $elref->{elem_attribs}{lc $attr} ; $metval = $elref->{elem_attribs}{uc $attr} if defined $elref->{elem_attribs}{uc $attr} ; } else { my $nattr = $attr; $nattr =~ s/^#//; $metval = $pref->{$nattr} if defined $pref->{$nattr} ; $metval = $pref->{lc $nattr} if defined $pref->{lc $nattr} ; $metval = $pref->{uc $nattr} if defined $pref->{uc $nattr} ; } # | is special char for em, repalce it if it is in value $metval =~ s/\|+/_/g; # do this special for _NULL values change them to NULL $metval = 'NULL' if $metval =~ /^_NULL$/; # validate metric value , data type checks if ( $has::Common::has_metric_config{data_type}{$metric_name}{$attr} ) { my $datatype = $has::Common::has_metric_config{data_type}{$metric_name}{$attr}; if ( $datatype =~ /number/i ) { $metval = 0 if $metval =~ /^NULL$/; $metval = 0 unless $metval; $metval = 0 unless defined $metval; warn "WARN:Invalid metric value $metval for metric column $attr for metic $metric_name not a number" and next unless $metval =~ /\d*/; } elsif ( $datatype =~ /boolean/ ) { $metval = 1 if $metval =~ /YES|TRUE/i; $metval = 0 if $metval =~ /NO|FALSE/i; $metval = 0 if $metval =~ /^NULL$/; warn "WARN:Invalid metric value $metval for metric column $attr for metic $metric_name not a boolean" and next unless $metval =~ /\d+/ and ( $metval == 0 or $metval == 1 ); } } $hashret{$attr} = $metval; } } # check for keys before pushing my $key_valid = 1; for my $kno ( keys %{$has::Common::has_metric_config{key_fields}{$metric_name}} ) { my $keyval = ""; for my $keypos ( sort { $a <=>$b } keys %{$has::Common::has_metric_config{key_fields}{$metric_name}{$kno}} ) { my $keycolval; my $keyattr; $keyattr = $has::Common::has_metric_config{key_fields}{$metric_name}{$kno}{$keypos}; $keycolval = $hashret{$keyattr} if $hashret{$keyattr}; $keycolval = $hashret{uc $keyattr} if $hashret{uc $keyattr}; $keycolval = $hashret{lc $keyattr} if $hashret{lc $keyattr}; if ( not $keycolval and $has::Common::has_metric_config{data_type}{$metric_name} and $has::Common::has_metric_config{data_type}{$metric_name}{$keyattr} and $has::Common::has_metric_config{data_type}{$metric_name}{$keyattr} =~ /number/) { $keycolval = $hashret{$keyattr} if defined $hashret{$keyattr}; } # key value cannot be null warn "WARN:Key column $keyattr is null while instrumenting metric $metric_name " and $key_valid = 0 and last unless defined $keycolval; $keyval = $keyval.'_'.$keycolval if defined $keycolval; } $keyval =~ s/^_// if $keyval; # if the key already exists then mark the key as invalid warn "WARN:Duplicate key $keyval while instrumenting metric $metric_name" and $key_valid = 0 if $rsref->{$metric_name.'_key_value'}{$kno}{$keyval}; # skip this metric row if key is invalid last unless $key_valid; # keep the list of keys $rsref->{$metric_name.'_key_value'}{$kno}{$keyval}=$retstr; $rsref->{hash_ref}{$metric_name}{$kno}{$keyval}=$elref; } # add the metric row only if key is valid push @{$rsref->{$metric_name}},$retstr if $key_valid;; } return 1; } # name : has_gen_key_value # desc : generate a key value for an element passed # # arg : # ref to hash opf element with attribs # metric_name being processed # # return : # key value # sub has_gen_key_value($$;) { my ( $elref,$metric_name) = @_; # for event metrics build the event key my $gen_key_value = ''; if ( $has::Common::has_metric_config{build_key}{$metric_name} ) { for my $ek ( sort keys %{$has::Common::has_metric_config{build_key_cols}{$metric_name}} ) { my $keycol = $has::Common::has_metric_config{build_key_cols}{$metric_name}{$ek}; my $keycolval = ''; if ( $elref->{elem_attribs}{$keycol} ) { $keycolval = $elref->{elem_attribs}{$keycol}; } elsif ( $elref->{elem_attribs}{uc $keycol} ) { $keycolval = $elref->{elem_attribs}{uc $keycol}; } elsif ( $elref->{elem_attribs}{lc $keycol} ) { $keycolval = $elref->{elem_attribs}{lc $keycol}; } if ( $gen_key_value ) { $gen_key_value = "$gen_key_value\_$keycolval"; } else { $gen_key_value = $keycolval; } } } return $gen_key_value; } # name : has_entity_fn # desc : for each element passed it filters our the enity element # # arg : # ref to xml element to be filtered # ref to xml ref to be returned back # metric_name being processed # crs home # filter metric column # filter metric column value # filter metric verb # sub has_entity_fn($$$;@) { my ( $elref, $rsref, $metric_name ,$crsHome, $args) = @_; my $filter_col; my $filter_val; my $filter_verb; my $dbPolicyManaged; ($filter_col,$filter_val,$filter_verb ) = @{$args} if $args and ref($args) =~/ARRAY/i; # check if this represents a element of interest return 1 unless $elref->{element} and $elref->{element} =~ /^entity$/i; # does this metric need instrumenting an entity type # if no entity type is defined the metric may be a cached from # another run return 1 unless $has::Common::has_metric_config{entity_type}{$metric_name}; return 1 unless $elref->{attrs} and $elref->{attrs}{entity_type} and $elref->{attrs}{entity_name} and $elref->{attrs}{entity_type} =~ /^$has::Common::has_metric_config{entity_type}{$metric_name}$/i; # save the cluster name and such globals as they are needed in every row to be printed $elref->{elem_attribs}{CLUSTER_NAME}= has::Common::hasGetClusterName($crsHome); $elref->{elem_attribs}{CLUSTER_ACTIVE_VERSION}= has::Common::hasGetClusterVersion($crsHome); $elref->{elem_attribs}{OS_HOST_NAME}= has::Common::hasGetLocalHostName(); $elref->{elem_attribs}{EM_TARGET_NAME}= $has::Common::has_em_targetname; $elref->{elem_attribs}{EM_TARGET_TYPE}= $has::Common::has_em_targettype; $elref->{elem_attribs}{EM_TARGET_GUID}= $has::Common::has_em_targetguid; $elref->{elem_attribs}{METRIC_SOURCE}= 'Fetchlet'; # event type for resource state change events if ( $has::Common::has_metric_config{entity_type}{$metric_name} and $has::Common::has_metric_config{entity_type}{$metric_name} =~ /resource|resource_instance/ ) { $elref->{elem_attribs}{EONS_EVENT_NAME}= 'CRS_RESOURCE_STATE_CHANGE'; } elsif ( $has::Common::has_metric_config{entity_type}{$metric_name} and $has::Common::has_metric_config{entity_type}{$metric_name} =~ /node|server/ ) { $elref->{elem_attribs}{EONS_EVENT_NAME}= 'CRS_SERVER_STATE_CHANGE'; } # the timestamp for the metric generation in GMT my $time = time; my ($sec,$min,$hr,$mday,$mon,$year,$wday,$yday) = gmtime($time); $year += 1900 if $year; $mon += 1 if $mon; my $timestring = sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hr,$min,$sec); $elref->{elem_attribs}{TIMESTAMP}= $timestring; # save entity type and entity name as elem attribs so they are # easy to print # when iterating over attribs to print $elref->{elem_attribs}{entity_type} = $elref->{attrs}{entity_type}; $elref->{elem_attribs}{entity_name} = $elref->{attrs}{entity_name}; # for now we kep oracle_name same as entity name $elref->{elem_attribs}{oracle_name} = $elref->{attrs}{entity_name}; # keep the root type, base_type_chain attribs if present $elref->{elem_attribs}{root_type} = $elref->{attrs}{root_type} if $elref->{attrs}{root_type}; $elref->{elem_attribs}{base_type_chain} = $elref->{attrs}{base_type_chain} if $elref->{attrs}{base_type_chain}; # check if it has attributes return 1 unless $elref->{children} and $elref->{child_elements}{attributes} and ref($elref->{child_elements}{attributes}) =~ /ARRAY/i and @{$elref->{child_elements}{attributes}}; my $attribsref = @{$elref->{child_elements}{attributes}}[0]; return 1 unless $attribsref->{children} and $attribsref->{child_elements}{attribute} and ref($attribsref->{child_elements}{attribute}) =~ /ARRAY/i and @{$attribsref->{child_elements}{attribute}}; my $valuefld = 'value'; $valuefld = $has::Common::has_metric_config{$metric_name}{value_property} if $has::Common::has_metric_config{$metric_name}{value_property}; my $attribbody=''; # create a name value array from the attributes for my $attribref ( @{$attribsref->{child_elements}{attribute}} ) { # get ref to the <name> and <[value]> element from attrib children my $nameref; my $valueref; next unless $attribref->{children}; for my $cref ( @{$attribref->{children}} ) { next unless $cref and $cref->{element} and $cref->{element} =~ /^(name|$valuefld)$/; $nameref = $cref if $cref->{element} =~ /^name$/; $valueref = $cref if $cref->{element} =~ /^$valuefld$/; } # if we do not get <name>xx</name> then skip this attribute next unless $nameref and $valueref and $nameref->{name}; my $value = $valueref->{name}; $elref->{elem_attribs}{$nameref->{name}}= $value; # save all the elements of the attribute as hash members in elref # this can be used for dependency values # added them as attribs not to confuse them with elem_attribs{name} # we mitght have a attribute name like MANDATORY etc # which matches element name MANDATORY for my $cref ( @{$attribref->{children}} ) { next unless $cref and $cref->{element}; $elref->{elem_attribs_properites}{$nameref->{name}}{$cref->{element}}= $cref->{name}; } $value='' unless defined $value; if ( $attribbody ) { $attribbody = "$attribbody$nameref->{name}=$value\;"; } else { $attribbody = "$nameref->{name}=$value\;"; } #cook up an RESOURCE_LOCATION attribute in attrib body # as eons event sends RESOURCE_LOCATION but not LAST_SERVER # and the gpnp callback looks for RESOURCE_LOCATION if ( $nameref->{name} =~ /^LAST_SERVER$/ ) { $attribbody = "$attribbody"."RESOURCE_LOCATION=$value\;"; } } # do the filteration based on filters passed if ( $filter_col and $filter_val ) { my $filter_column_value; if ( $elref->{elem_attribs}{$filter_col} ) { $filter_column_value = $elref->{elem_attribs}{$filter_col}; } elsif ( $elref->{elem_attribs}{uc $filter_col} ) { $filter_column_value = $elref->{elem_attribs}{uc $filter_col}; } elsif ( $elref->{elem_attribs}{lc $filter_col} ) { $filter_column_value = $elref->{elem_attribs}{lc $filter_col}; } if ( $filter_verb and $filter_verb =~ /NO/i ) { # filter rows with column values not like if ( not defined $filter_column_value and defined $filter_val ) { return 1; } if ( defined $filter_column_value and not defined $filter_val ) { return 1; } if ( defined $filter_column_value and defined $filter_val ) { return 1 if $filter_column_value =~ /$filter_val/; } } else { # filter rows with column values like if ( defined $filter_column_value and defined $filter_val ) { return 1 unless $filter_column_value =~ /$filter_val/; } } } # generate key value if required my $gen_key_value = has_gen_key_value($elref,$metric_name); $elref->{elem_attribs}{GENERATED_KEY_1}=$gen_key_value; # mark relocated for vip if ( $metric_name =~ /vip_relocation_metric|resource_instance_alert_metric/ ) { if ( $elref->{elem_attribs}{TYPE} =~ /ora.cluster_vip_net1.type/ ) { if ( $elref->{elem_attribs}{NAME} and $elref->{elem_attribs}{LAST_SERVER} ) { if ( $elref->{elem_attribs}{NAME} =~ /ora\.$elref->{elem_attribs}{LAST_SERVER}\.vip/ ) { $elref->{elem_attribs}{RELOCATED}='FALSE'; } else { $elref->{elem_attribs}{RELOCATED}='TRUE'; $elref->{elem_attribs}{ADDITIONAL_ALERT_MESSAGE}=" Relocated to Node $elref->{elem_attribs}{LAST_SERVER}" if $elref->{elem_attribs}{STATE} =~ /INTERMEDIATE/; } } else { $elref->{elem_attribs}{RELOCATED}='NotDefined'; } } } #generate any dependent metrics if they are to be instrumented # get the function name for instrumenting the dependent metrics from # the config hash for my $dp_metric_name ( keys %{$has::Common::has_metric_config{dependent_metric_functions}{$metric_name}} ) { warn "WARN:has::Common::has_dependencies:Failed to instrument dependent metric $dp_metric_name for $metric_name" unless $has::Common::has_metric_config{dependent_metric_functions}{$metric_name}{$dp_metric_name}; my $dp_retstr = &{$has::Common::has_metric_config{dependent_metric_functions}{$metric_name}{$dp_metric_name}} ($elref,$rsref,$dp_metric_name) or warn "WARN:has::Common::has_dependencies:Failed to instrument dependent metric $dp_metric_name for $metric_name" and next; if ( $metric_name =~ /gpnp_alert_metric/ and $dp_metric_name =~ /gpnp_server_pool/ ) { my $sglist; $sglist = $elref->{elem_attribs}{SERVER_POOLS} if $elref and ref($elref) =~ /HASH/i and $elref->{elem_attribs} and $elref->{elem_attribs}{SERVER_POOLS}; my $rtype; $rtype = $elref->{elem_attribs}{TYPE} if $elref->{elem_attribs}{TYPE}; if ( $rtype and $rtype =~ /ora.database.type/ ) { if ( $sglist ) { my @sgs = split /\s+/,$sglist if $sglist; for my $sg ( @sgs ) { $sg =~ s/^\s+|\s+$//; next unless $sg; if ( $rsref and ref($rsref) =~ /HASH/i and $rsref->{$dp_metric_name} and keys %{$rsref->{$dp_metric_name}} and $rsref->{$dp_metric_name}{$sg} ) { my $pp = $rsref->{$dp_metric_name}{$sg}{PARENT_POOLS} if $rsref->{$dp_metric_name}{$sg}{PARENT_POOLS}; $pp =~ s/\s+//g if $pp; # if the server pools do no thave parent pools then it is policy managed # an admin managed db can have only one server pool if ( $pp ) { $dbPolicyManaged = 'NO' if @sgs < 2; $dbPolicyManaged = 'YES' if @sgs > 1; } else { $dbPolicyManaged = 'YES'; last if @sgs > 1; } } else { $dbPolicyManaged = 'NO' if @sgs < 2; $dbPolicyManaged = 'YES' if @sgs > 1; } } } else { $dbPolicyManaged = 'NO'; } } } } if ( $dbPolicyManaged ) { if ( $attribbody ) { $attribbody="DB_POLICY_MANAGED_COMPUTED=$dbPolicyManaged\;$attribbody"; } else { $attribbody="DB_POLICY_MANAGED_COMPUTED=$dbPolicyManaged\;"; } } if ( $attribbody ) { $elref->{elem_attribs}{ATTRIB_BODY}=$attribbody; $elref->{elem_attribs}{ATTRIB_BODY1}=substr($attribbody,0,2000); if ( length($attribbody) > 2000 ) { $elref->{elem_attribs}{ATTRIB_BODY2}=substr($attribbody,2000,2000); } } # build the em_results row has::Common::has_em_results($elref,$rsref,$metric_name); return 1; } # name : has_gpnp_server_pool_fn # desc : for each element passed it filters our the enity element # # arg : # ref to xml element to be filtered # ref to xml ref to be returned back # metric_name being processed # crs home # filter metric column # filter metric column value # filter metric verb # sub has_gpnp_server_pool_fn($$$;@) { my ( $elref, $rsref, $metric_name ,$crsHome, $args) = @_; my $filter_col; my $filter_val; my $filter_verb; ($filter_col,$filter_val,$filter_verb ) = @{$args} if $args and ref($args) =~/ARRAY/i; # check if this represents a element of interest return 1 unless $elref->{element} and $elref->{element} =~ /^entity$/i; # does this metric need instrumenting an entity type # if no entity type is defined the metric may be a cached from # another run return 1 unless $has::Common::has_metric_config{entity_type}{$metric_name}; return 1 unless $elref->{attrs} and $elref->{attrs}{entity_type} and $elref->{attrs}{entity_name} and $elref->{attrs}{entity_type} =~ /^$has::Common::has_metric_config{entity_type}{$metric_name}$/i; # save entity type and entity name as elem attribs so they are # easy to print # when iterating over attribs to print $elref->{elem_attribs}{entity_type} = $elref->{attrs}{entity_type}; $elref->{elem_attribs}{entity_name} = $elref->{attrs}{entity_name}; # check if it has attributes return 1 unless $elref->{children} and $elref->{child_elements}{attributes} and ref($elref->{child_elements}{attributes}) =~ /ARRAY/i and @{$elref->{child_elements}{attributes}}; my $attribsref = @{$elref->{child_elements}{attributes}}[0]; return 1 unless $attribsref->{children} and $attribsref->{child_elements}{attribute} and ref($attribsref->{child_elements}{attribute}) =~ /ARRAY/i and @{$attribsref->{child_elements}{attribute}}; my $valuefld = 'value'; $valuefld = $has::Common::has_metric_config{$metric_name}{value_property} if $has::Common::has_metric_config{$metric_name}{value_property}; my $attribbody=''; # create a name value array from the attributes for my $attribref ( @{$attribsref->{child_elements}{attribute}} ) { # get ref to the <name> and <[value]> element from attrib children my $nameref; my $valueref; next unless $attribref->{children}; for my $cref ( @{$attribref->{children}} ) { next unless $cref and $cref->{element} and $cref->{element} =~ /^(name|$valuefld)$/; $nameref = $cref if $cref->{element} =~ /^name$/; $valueref = $cref if $cref->{element} =~ /^$valuefld$/; } # if we do not get <name>xx</name> then skip this attribute next unless $nameref and $valueref and $nameref->{name}; my $value = $valueref->{name}; $elref->{elem_attribs}{$nameref->{name}}= $value; # save all the elements of the attribute as hash members in elref # this can be used for dependency values # added them as attribs not to confuse them with elem_attribs{name} # we mitght have a attribute name like MANDATORY etc # which matches element name MANDATORY for my $cref ( @{$attribref->{children}} ) { next unless $cref and $cref->{element}; $elref->{elem_attribs_properites}{$nameref->{name}}{$cref->{element}}= $cref->{name}; } $value='' unless defined $value; } if ( $elref and $elref->{elem_attribs} and $elref->{elem_attribs}{NAME} and ref($elref->{elem_attribs}) =~ /HASH/i and keys %{$elref->{elem_attribs}} ) { for my $attrib ( keys %{$elref->{elem_attribs}} ) { $rsref->{$metric_name}{$elref->{elem_attribs}{NAME}} {$attrib} = $elref->{elem_attribs}{$attrib}; } } return 1; } # name : has_resource_crs_servers_fn # desc : for each element passed it filters our the enity element # # arg : # ref to xml element to be filtered # ref to xml ref to be returned back # metric_name being processed # crs home # filter metric column # filter metric column value # filter metric verb # sub has_resource_crs_servers_fn($$$;@) { my ( $elref, $rsref, $metric_name ,$crsHome, $args) = @_; my $filter_col; my $filter_val; my $filter_verb; ($filter_col,$filter_val,$filter_verb ) = @{$args} if $args and ref($args) =~/ARRAY/i; # check if this represents a element of interest return 1 unless $elref->{element} and $elref->{element} =~ /^entity$/i; # does this metric need instrumenting an entity type # if no entity type is defined the metric may be a cached from # another run return 1 unless $has::Common::has_metric_config{entity_type}{$metric_name}; return 1 unless $elref->{attrs} and $elref->{attrs}{entity_type} and $elref->{attrs}{entity_name} and $elref->{attrs}{entity_type} =~ /^$has::Common::has_metric_config{entity_type}{$metric_name}$/i; # save the cluster name and such globals as they are needed in every row to be printed $elref->{elem_attribs}{METRIC_SOURCE}= 'Fetchlet'; # event type for resource state change events $elref->{elem_attribs}{EONS_EVENT_NAME}= 'CRS_SERVER_STATE_CHANGE'; # the timestamp for the metric generation in GMT my $time = time; my ($sec,$min,$hr,$mday,$mon,$year,$wday,$yday) = gmtime($time); $year += 1900 if $year; $mon += 1 if $mon; my $timestring = sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hr,$min,$sec); $elref->{elem_attribs}{TIMESTAMP}= $timestring; # save entity type and entity name as elem attribs so they are # easy to print # when iterating over attribs to print $elref->{elem_attribs}{entity_type} = $elref->{attrs}{entity_type}; $elref->{elem_attribs}{entity_name} = $elref->{attrs}{entity_name}; # for now we kep oracle_name same as entity name $elref->{elem_attribs}{oracle_name} = $elref->{attrs}{entity_name}; # check if it has attributes return 1 unless $elref->{children} and $elref->{child_elements}{attributes} and ref($elref->{child_elements}{attributes}) =~ /ARRAY/i and @{$elref->{child_elements}{attributes}}; my $attribsref = @{$elref->{child_elements}{attributes}}[0]; return 1 unless $attribsref->{children} and $attribsref->{child_elements}{attribute} and ref($attribsref->{child_elements}{attribute}) =~ /ARRAY/i and @{$attribsref->{child_elements}{attribute}}; my $valuefld = 'value'; $valuefld = $has::Common::has_metric_config{$metric_name}{value_property} if $has::Common::has_metric_config{$metric_name}{value_property}; my $attribbody=''; # create a name value array from the attributes for my $attribref ( @{$attribsref->{child_elements}{attribute}} ) { # get ref to the <name> and <[value]> element from attrib children my $nameref; my $valueref; next unless $attribref->{children}; for my $cref ( @{$attribref->{children}} ) { next unless $cref and $cref->{element} and $cref->{element} =~ /^(name|$valuefld)$/; $nameref = $cref if $cref->{element} =~ /^name$/; $valueref = $cref if $cref->{element} =~ /^$valuefld$/; } # if we do not get <name>xx</name> then skip this attribute next unless $nameref and $valueref and $nameref->{name}; my $value = $valueref->{name}; $elref->{elem_attribs}{$nameref->{name}}= $value; # save all the elements of the attribute as hash members in elref # this can be used for dependency values # added them as attribs not to confuse them with elem_attribs{name} # we mitght have a attribute name like MANDATORY etc # which matches element name MANDATORY for my $cref ( @{$attribref->{children}} ) { next unless $cref and $cref->{element}; $elref->{elem_attribs_properites}{$nameref->{name}}{$cref->{element}}= $cref->{name}; } $value='' unless defined $value; if ( $attribbody ) { $attribbody = "$attribbody$nameref->{name}=$value\;"; } else { $attribbody = "$nameref->{name}=$value\;"; } } if ( $attribbody ) { $elref->{elem_attribs}{ATTRIB_BODY}=$attribbody; $elref->{elem_attribs}{ATTRIB_BODY1}=substr($attribbody,0,2000); if ( length($attribbody) > 2000 ) { $elref->{elem_attribs}{ATTRIB_BODY2}=substr($attribbody,2000,2000); } } # generate key value if required my $gen_key_value = has_gen_key_value($elref,$metric_name); $elref->{elem_attribs}{GENERATED_KEY_1}=$gen_key_value; if ( $elref and $elref->{elem_attribs} and $elref->{elem_attribs}{NAME} and ref($elref->{elem_attribs}) =~ /HASH/i and keys %{$elref->{elem_attribs}} ) { for my $attrib ( keys %{$elref->{elem_attribs}} ) { $rsref->{$metric_name}{$elref->{elem_attribs}{NAME}} {$attrib} = $elref->{elem_attribs}{$attrib}; } } return 1; } #------------------------------------------------------------------------------ # FUNCTION : fnnpprnd # # DESC # print each node , to be called from the depth first tree traversal fn # prints the nested tree with braces # # ARGUMENTS # node, # traverse tag # stack # string to print # hash of depth and nodes to be closed # # RETURN #------------------------------------------------------------------------------ sub fnnpprnd ( $$$$$ ) { my ($node, $tvtag , $stack_ref, $strg_ref, $has_indnthsh) = @_; warn "WARN:has::Common::fnnpprnd:entity passed is not a reference\n" and return unless ref($node); $$strg_ref='' unless $$strg_ref; my $type = 'resource'; #start to print from relationships, do not print root nodes if ( not $node->{entity_type} or $node->{entity_type} !~/relationship/ ) { $$strg_ref = "$$strg_ref(" and return 1; } $$strg_ref="$$strg_ref("; if ( $node->{type} ) { $$strg_ref="$$strg_ref$node->{type}:"; } else { $$strg_ref="$$strg_ref:"; } if ( $node->{attrib1} and $node->{attrib1} !~ /^NA$/ ) { $$strg_ref="$$strg_ref$node->{attrib1}:"; } else { $$strg_ref="$$strg_ref:"; } if ( $node->{attrib2} and $node->{attrib2} !~ /NA/ ) { $$strg_ref="$$strg_ref$node->{attrib2}:"; $type = 'resourcetype' if $node->{attrib2} =~ /^type$/ and $tvtag !~ /^dependents$/; } else { $$strg_ref="$$strg_ref:"; } $$strg_ref="$$strg_ref<$type>"; if ( $node->{resource} ) { $$strg_ref="$$strg_ref$node->{resource}"; } $$strg_ref="$$strg_ref</$type>"; return 1 if defined $node->{$tvtag} and $node->{$tvtag} and keys %{$node->{$tvtag}}; # close any parent nodes that need to be closed # How deep is the node for ( sort {$b<=>$a} keys %{$stack_ref} ) { # if there are children at a particular level, then do not close the braces $$strg_ref="$$strg_ref, " and last if $has_indnthsh->{$_}; $$strg_ref="$$strg_ref)"; } return 1; } #------------------------------------------------------------------------------ # FUNCTION : fnnpprdp # # DESC # mark depth and parent for each node , to be called from the depth first tree traversal fn # # ARGUMENTS # node, # traverse tag # stack # string to print # hash of depth and nodes to be closed # # RETURN #------------------------------------------------------------------------------ sub fnnpprdp ( $$$$$ ) { my ($node, $tvtag , $stack_ref, $strg_ref, $has_indnthsh) = @_; warn "WARN:has::Common::fnnpprdp:entity passed is not a reference\n" and return unless ref($node); my $depth = 0; # close any parent nodes that need to be closed # How deep is the node for ( sort {$b<=>$a} keys %{$stack_ref} ) { $depth = $_; last; } $node->{depth}=$depth; return 1; } #------------------------------------------------------------------------------ # FUNCTION : fnnpprnb # # DESC # print each node , to be called from the breadth first tree traversal fn # keeps an hash of the string of resources by depth # # ARGUMENTS # node, # traverse tag # ref to hash of results # # RETURN #------------------------------------------------------------------------------ sub fnnpprnb ( $$$ ) { my ($node, $tvtag , $res_ref ) = @_; warn "WARN:has::Common::fnnpprnb:entity passed is not a reference\n" and return unless ref($node); warn "WARN:has::Common::fnnpprnb:entity passed does not have a name \n" and return unless $node->{resource}; my $type = 'resource'; my $strg; #start to print from relationships, do not print root nodes if ( not $node->{entity_type} or $node->{entity_type} !~/relationship/ ) { return 1; } if ( $node and $node->{depth} and $node->{depth} == 1 ) { return 1; } warn "WARN:has::Common::fnnpprnb:entity passed does not have a dependee \n" and return unless $node->{dependee}; return 1 if $res_ref and $res_ref->{key} and $res_ref->{key}{$node->{dependee}} and $res_ref->{key}{$node->{dependee}}{$node->{resource}}; if ( $node->{type} ) { $strg = 'START' if $node->{type} =~ /START_DEP/; $strg = 'STOP' if $node->{type} =~ /STOP_DEP/; } if ( $node->{attrib1} and $node->{attrib1} !~ /^NA$/ ) { $strg="$strg:$node->{attrib1}:"; } if ( $node->{attrib2} and $node->{attrib2} !~ /NA/ ) { $type = 'resourcetype' if $node->{attrib2} =~ /^type$/ and $tvtag !~ /^dependents$/; } $strg="$strg<$type>"; if ( $node->{resource} ) { $strg="$strg$node->{resource}"; } $strg="$strg</$type>"; $res_ref->{key}{$node->{dependee}}{$node->{resource}}=1; $res_ref->{results}{$node->{dependee}} = "$res_ref->{results}{$node->{dependee}},$strg" if $res_ref->{results}{$node->{dependee}}; $res_ref->{results}{$node->{dependee}}=$strg unless $res_ref->{results}{$node->{dependee}}; return 1 if defined $node->{$tvtag} and $node->{$tvtag} and keys %{$node->{$tvtag}}; $res_ref->{results}{$node->{resource}}=''; return 1; } #------------------------------------------------------------------------------ # FUNCTION : hasGetResourceDependencyString # # DESC # return the resource dependency as a string # # ARGUMENTS # crsHome if known # # RETURN # ref to the hash to be filled in with values #------------------------------------------------------------------------------ sub hasGetResourceDependencyString($;) { my ( $crsHome ) = @_; # get the resource information my $cmd='emcrsp em config -e resource'; my $reslistref; # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { $crsHome = has::Common::hasGetCRSHome(); # get the cluster home by discovery if ( not $crsHome or not has::Common::hasCheckForEmcrsp($crsHome) ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } return $reslistref and warn "WARN:has::Common::hasGetResourceDependencyString:Cluster home is not passed or not set in env" unless $crsHome; return $reslistref and warn "DEBUG:has::Common::hasGetResourceDependencyString:binary emcrsp is not present in $crsHome" unless has::Common::hasCheckForEmcrsp($crsHome); has::Common::hasSetCRSEnv($crsHome); my $cmdresults = has::Common::runsystemcommand($cmd); has::Common::hasRestoreCRSEnv(); warn "WARN:has::Common::hasGetResourceDependencyString Failed to get results from command - $cmd" and return $reslistref unless $cmdresults; my %xmlvar = has::Common::parse_xml($cmdresults); $has::Common::has_metric_config{dependent_metric_functions}{resources} = { resource_dependencies => \&has::Common::has_dependencies, }; my %resulthash; has::Common::traverse_xml(\%xmlvar,\&has::Common::has_handle_error,\&has_entity_fn,\%resulthash,'resources'); return unless $resulthash{resource_dependencies}; my @rows = @{$resulthash{resource_dependencies}}; my $rel = 0; my $depends_rel_index; my $dependent_rel_index; my $depends_on_index; my $dependent_index; for my $row ( @rows ) { $row =~ s/^\s+|\s+$// if $row; chomp($row); next unless $row; $row =~ s/^em_result=//g; my @rowcols = split/\|/,$row; my ( $cn,$res,$typ,$child,$atb1,$atb2) = @rowcols; $rel++; # e.g. this is the relationship rel where there is an dependency on emres2 for emres1 $depends_rel_index->{$rel} = { entity_type=>'relationship', type=>$typ, resource=>$child, attrib1=>$atb1, attrib2=>$atb2 }; # e.g. this is the relationship rel where there is an dependency where emres1 depends on emres2 $dependent_rel_index->{$rel} = { entity_type=>'relationship', type=>$typ, resource=>$res, attrib1=>$atb1, attrib2=>$atb2 }; # this is the start|stop dependencies of a resource # e.g. resource emres1 depends on resource emres2 $depends_on_index->{depends_on}{$res}{depends_on}{$rel}=$rel; $depends_on_index->{depends_on}{$res}{resource}=$res; $depends_on_index->{depends_on}{$res}{entity_type}='resource'; # resources that depend on a given resource # e.g. resource emres2 has resource emres1 dependent on it thru relation rel #$dependent_index->{dependents}{$child}{$rel}=$res; $dependent_index->{dependents}{$child}{dependents}{$rel}=$rel; $dependent_index->{dependents}{$child}{resource}=$child; $dependent_index->{dependents}{$child}{entity_type}='resource'; } # for each resource that depends on a given resource # for each resource that are dependents of emres2 if ( $dependent_index and $dependent_index->{dependents} ) { for my $resnm ( keys %{$dependent_index->{dependents}} ) { # are there other resources that this resource depends on # is emres2 in turn dependent on other resources next unless $depends_on_index and $depends_on_index->{depends_on} and $depends_on_index->{depends_on}{$resnm}; # for every relationship where you have another resource dependening on this # resource mark that it has dependencies on other resources in turn # take the dependents emres2 and slap them on to all relationships # where other resources are dependent on emres2, so you get the chain of dependents for my $rel ( keys %{$dependent_index->{dependents}{$resnm}{dependents}} ) { for my $upperrel ( keys %{$depends_on_index->{depends_on}{$resnm}{depends_on}} ) { $depends_rel_index->{$rel}{depends_on}{$upperrel}=$upperrel; } } } } # for each resource that depends on other resource # for each resource that emres1 depends on if ( $depends_on_index and $depends_on_index->{depends_on} ) { for my $resnm ( keys %{$depends_on_index->{depends_on}} ) { # are there other resources that are dependents of this # other resources which are dependent on emres2 next unless $dependent_index and $dependent_index->{dependents} and $dependent_index->{dependents}{$resnm}; # for every relationship where you have another resource dependening on this # resource mark that it has dependencies on other resources in turn # take the dependents emres2 and slap them on to all relationships # where other resources are dependent on emres2, so you get the chain of dependents for my $rel ( keys %{$depends_on_index->{depends_on}{$resnm}{depends_on}} ) { for my $upperrel ( keys %{$dependent_index->{dependents}{$resnm}{dependents}} ) { $dependent_rel_index->{$rel}{dependents}{$upperrel}=$upperrel; } } } } my %has_sort_dep_index; my %res; for my $key ( keys %{$depends_on_index->{depends_on}} , keys %{$dependent_index->{dependents}} ) { my $node; my $strg; next if $has_sort_dep_index{$key}; $has_sort_dep_index{$key}=1; if ( $depends_on_index->{depends_on}{$key} ) { $node = $depends_on_index->{depends_on}{$key}; fntrdf('preorder',$node,'depends_on',$depends_rel_index,&fnnpprnd,\$strg); $res{$key}{dependent_on}=$strg if $strg; } next unless $dependent_index->{dependents}{$key}; $node = $dependent_index->{dependents}{$key}; $strg=''; fntrdf('preorder',$node,'dependents',$dependent_rel_index,&fnnpprnd,\$strg); $res{$key}{dependents}=$strg if $strg; } return \%res; } #------------------------------------------------------------------------------ # FUNCTION : hasGetResourceDependents # # DESC # return the resource dependets as a couple # # ARGUMENTS # crsHome if known # # RETURN # ref to the hash to be filled in with values #------------------------------------------------------------------------------ sub hasGetResourceDependents($;) { my ( $crsHome ) = @_; # get the resource information my $cmd='emcrsp em config -e resource'; my $reslistref; # no cluster home is passed then # get the cluster home from the env # and if not available or no emcrsp then discover one if ( not $crsHome ) { $crsHome = has::Common::hasGetCRSHome(); # get the cluster home by discovery if ( not $crsHome or not has::Common::hasCheckForEmcrsp($crsHome) ) { $crsHome = has::Common::hasGetEnvCRSHome(); } } return $reslistref and warn "WARN:has::Common::hasGetResourceDependents:Cluster home is not passed or not set in env" unless $crsHome; return $reslistref and warn "DEBUG:has::Common::hasGetResourceDependents:binary emcrsp is not present in $crsHome" unless has::Common::hasCheckForEmcrsp($crsHome); has::Common::hasSetCRSEnv($crsHome); my $cmdresults = has::Common::runsystemcommand($cmd); has::Common::hasRestoreCRSEnv(); warn "WARN:has::Common::hasGetResourceDependents Failed to get results from command - $cmd" and return $reslistref unless $cmdresults; my %xmlvar = has::Common::parse_xml($cmdresults); $has::Common::has_metric_config{dependent_metric_functions}{resources} = { resource_dependencies => \&has::Common::has_dependencies, }; my %resulthash; has::Common::traverse_xml(\%xmlvar,\&has::Common::has_handle_error,\&has_entity_fn,\%resulthash,'resources'); return unless $resulthash{resource_dependencies}; my @rows = @{$resulthash{resource_dependencies}}; my $rel = 0; my $depends_rel_index; my $dependent_rel_index; my $depends_on_index; my $dependent_index; for my $row ( @rows ) { $row =~ s/^\s+|\s+$// if $row; chomp($row); next unless $row; $row =~ s/^em_result=//g; my @rowcols = split/\|/,$row; my ( $cn,$res,$typ,$child,$atb1,$atb2) = @rowcols; $rel++; # e.g. this is the relationship rel where there is an dependency where emres1 depends on emres2 $dependent_rel_index->{$rel} = { dependee=>$child, entity_type=>'relationship', type=>$typ, resource=>$res, attrib1=>$atb1, attrib2=>$atb2 }; # e.g. this is the relationship rel where there is an dependency on emres2 for emres1 $depends_rel_index->{$rel} = { entity_type=>'relationship', type=>$typ, resource=>$child, attrib1=>$atb1, attrib2=>$atb2 }; # this is the start|stop dependencies of a resource # e.g. resource emres1 depends on resource emres2 $depends_on_index->{depends_on}{$res}{depends_on}{$rel}=$rel; $depends_on_index->{depends_on}{$res}{resource}=$res; $depends_on_index->{depends_on}{$res}{entity_type}='resource'; # resources that depend on a given resource # e.g. resource emres2 has resource emres1 dependent on it thru relation rel #$dependent_index->{dependents}{$child}{$rel}=$res; $dependent_index->{dependents}{$child}{dependents}{$rel}=$rel; $dependent_index->{dependents}{$child}{resource}=$child; $dependent_index->{dependents}{$child}{entity_type}='resource'; } # for each resource that depends on other resource # for each resource that emres1 depends on if ( $depends_on_index and $depends_on_index->{depends_on} ) { for my $resnm ( keys %{$depends_on_index->{depends_on}} ) { # are there other resources that are dependents of this # other resources which are dependent on emres2 next unless $dependent_index and $dependent_index->{dependents} and $dependent_index->{dependents}{$resnm}; # for every relationship where you have another resource dependening on this # resource mark that it has dependencies on other resources in turn # take the dependents emres2 and slap them on to all relationships # where other resources are dependent on emres2, so you get the chain of dependents for my $rel ( keys %{$depends_on_index->{depends_on}{$resnm}{depends_on}} ) { for my $upperrel ( keys %{$dependent_index->{dependents}{$resnm}{dependents}} ) { $dependent_rel_index->{$rel}{dependents}{$upperrel}=$upperrel; } } } } my %has_sort_dep_index; my %res; for my $key ( keys %{$dependent_index->{dependents}} ) { my $node; my %dep_res = (); my $strg = ''; next if $has_sort_dep_index{$key}; $has_sort_dep_index{$key}=1; $node = $dependent_index->{dependents}{$key}; #fntrdf('preorder',$node,'dependents',$dependent_rel_index,&fnnpprdp,\$strg); fntrbf('preorder',$node,'dependents',$dependent_rel_index,&fnnpprnb,\%dep_res); $res{$key}=$dep_res{results} if $dep_res{results}; } return \%res; } 1;
Ms-Dos/Windows
Unix
Write backup
jsp File Browser version 1.2 by
www.vonloesch.de