diff --git a/lib/sles4sap.pm b/lib/sles4sap.pm index 9ef3257b7aa9..462e7b024b13 100644 --- a/lib/sles4sap.pm +++ b/lib/sles4sap.pm @@ -67,12 +67,8 @@ our @EXPORT = qw( prepare_sapinst_profile netweaver_installation_data prepare_swpm - sapcontrol_process_check get_sidadm - sap_show_status_info - sapcontrol get_instance_profile_path - get_remote_instance_number load_ase_env upload_ase_logs ); @@ -1360,214 +1356,6 @@ sub get_sidadm { return $sidadm; } -=head2 sap_show_status_info - - $self->sap_show_status_info(cluster=>1, netweaver=>1); - -Prints output for standard set of commands to show info about system in various stages of the test for troubleshooting. -It is possible to activate or deactivate various output sections by named args: - -B - Shows cluster related outputs - -B - Shows netweaver related outputs - -=cut - -sub sap_show_status_info { - my ($self, %args) = @_; - my $cluster = $args{cluster}; - my $netweaver = $args{netweaver}; - my $instance_id = defined($netweaver) ? $args{instance_id} : get_required_var('INSTANCE_ID'); - my @output; - - # Netweaver info - if (defined($netweaver)) { - push(@output, "\n//// NETWEAVER ///"); - push(@output, "\n### SAPCONTROL PROCESS LIST ###"); - push(@output, $self->sapcontrol(instance_id => $instance_id, webmethod => 'GetProcessList', return_output => 1)); - push(@output, "\n### SAPCONTROL SYSTEM INSTANCE LIST ###"); - push(@output, $self->sapcontrol(instance_id => $instance_id, webmethod => 'GetSystemInstanceList', return_output => 1)); - } - - # Cluster info - if (defined($cluster)) { - push(@output, "\n//// CLUSTER ///"); - push(@output, "\n### CLUSTER STATUS ###"); - push(@output, script_output('PAGER=/usr/bin/cat crm status')); - } - record_info('Status', join("\n", @output)); -} - -=head2 sapcontrol - - $self->sapcontrol(instance_id=>$instance_id, - webmethod=>$webmethod, - [additional_args=>$additional_args, - remote_execution=>$remote_execution]); - -Executes sapcontrol webmethod for instance specified in arguments and returns exit code received from command. -Allows remote execution of webmethods between instances, however not all webmethods are possible to execute in that manner. - -Sapcontrol return codes: - - RC 0 = webmethod call was successful - RC 1 = webmethod call failed - RC 2 = last webmethod call in progress (processes are starting/stopping) - RC 3 = all processes GREEN - RC 4 = all processes GREY (stopped) - -B 2 digit instance number - -B webmethod name to be executed (Ex: Stop, GetProcessList, ...) - -B additional arguments to be appended at the end of command - -B returns output instead of RC - -B hostname of the target instance for remote execution. Local execution does not need this. - -B Password for sidadm user. Only required for remote execution. - -=cut - -sub sapcontrol { - my ($self, %args) = @_; - my $webmethod = $args{webmethod}; - my $instance_id = $args{instance_id}; - my $remote_hostname = $args{remote_hostname}; - my $return_output = $args{return_output}; - my $additional_args = $args{additional_args} // ''; - my $sidadm = $self->get_sidadm(); - my $current_user = script_output_retry_check(cmd => 'whoami', sleep => 2, regex_string => "^root\$|^$sidadm\$"); - my $sidadm_password = $args{sidadm_password}; - - croak "Mandatory argument 'webmethod' not specified" unless $webmethod; - croak "Mandatory argument 'instance_id' not specified" unless $instance_id; - croak "Function may be executed under root or sidadm.\nCurrent user: $current_user" - unless grep(/$current_user/, ('root', $sidadm)); - - my $cmd = join(' ', 'sapcontrol', '-nr', $instance_id); - # variables below allow sapcontrol to run under root - my $sapcontrol_path_root = '/usr/sap/hostctrl/exe'; - my $root_env = "LD_LIBRARY_PATH=$sapcontrol_path_root:\$LD_LIBRARY_PATH"; - $cmd = $current_user eq 'root' ? "$root_env $sapcontrol_path_root/$cmd" : $cmd; - - if ($remote_hostname) { - croak "Mandatory argument 'sidadm_password' not specified" unless $sidadm_password; - $cmd = join(' ', $cmd, '-host', $remote_hostname, '-user', $sidadm, $sidadm_password); - } - $cmd = join(' ', $cmd, '-function', $webmethod); - $cmd = join(' ', $cmd, $additional_args) if $additional_args; - - my $result = $return_output ? script_output($cmd, proceed_on_failure => 1) : script_run($cmd); - - return ($result); -} - -=head2 sapcontrol_process_check - - $self->sapcontrol_process_check(expected_state=>expected_state, - [instance_id=>$instance_id, - loop_sleep=>$loop_sleep, - timeout=>$timeout, - wait_for_state=>$wait_for_state]); - -Runs "sapcontrol -nr -function GetProcessList" via SIDadm and compares RC against expected state. -Croaks if state is not correct. - -Expected return codes are: - - RC 0 = webmethod call was successfull - RC 1 = webmethod call failed (This includes NIECONN_REFUSED status) - RC 2 = last webmethod call in progress (processes are starting/stopping) - RC 3 = all processes GREEN - RC 4 = all processes GREY (stopped) - -Method arguments: - -B State that is expected (failed, started, stopped) - -B Instance number - two digit number - -B sleep time between checks - only used if 'wait_for_state' is true - -B timeout for waiting for target state, after which function croaks - -B If set to true, function will wait for expected state until success or timeout - -=cut - -sub sapcontrol_process_check { - my ($self, %args) = @_; - my $instance_id = $args{instance_id} // get_required_var('INSTANCE_ID'); - my $expected_state = $args{expected_state}; - my $loop_sleep = $args{loop_sleep} // 5; - my $timeout = $args{timeout} // bmwqemu::scale_timeout(120); - my $wait_for_state = $args{wait_for_state} // 0; - my %state_to_rc = ( - failed => '1', # After stopping service (ServiceStop method) sapcontrol returns RC1 - started => '3', - stopped => '4' - ); - - croak "Argument 'expected state' undefined" unless defined($expected_state); - - my @allowed_state_values = keys(%state_to_rc); - $expected_state = lc $expected_state; - croak "Value '$expected_state' for argument 'expected state' not supported. Allowed values: '@allowed_state_values'" - unless (grep(/^$expected_state$/, @allowed_state_values)); - - my $rc = $self->sapcontrol(instance_id => $instance_id, webmethod => 'GetProcessList'); - my $start_time = time; - - while ($rc ne $state_to_rc{$expected_state}) { - last unless $wait_for_state; - $rc = $self->sapcontrol(instance_id => $instance_id, webmethod => 'GetProcessList'); - croak "Timeout while waiting for expected state: $expected_state" if (time - $start_time > $timeout); - sleep $loop_sleep; - } - - if ($state_to_rc{$expected_state} ne $rc) { - $self->sap_show_status_info(netweaver => 1, instance_id => $instance_id); - croak "Processes are not '$expected_state'"; - } - - return $expected_state; -} - -=head2 get_remote_instance_number - - $self->get_instance_number(instance_type=>$instance_type); - -Finds instance number from remote instance using sapcontrol "GetSystemInstanceList" webmethod. -Local system instance number is required to execute sapcontrol though. - -B Instance type (ASCS, ERS) - this can be expanded to other instances - -=cut - -sub get_remote_instance_number () { - my ($self, %args) = @_; - my $instance_type = $args{instance_type}; - my $local_instance_id = get_required_var('INSTANCE_ID'); - - croak "Missing mandatory argument '$instance_type'." unless $instance_type; - croak "Function is not yet implemented for instance type: $instance_type" unless grep /$instance_type/, ('ASCS', 'ERS'); - - # This needs to be expanded for PAS and AAS - my %instance_type_features = ( - ASCS => 'MESSAGESERVER', - ERS => 'ENQREP' - ); - - my @instance_data = grep /$instance_type_features{$instance_type}/, - split('\n', $self->sapcontrol(webmethod => 'GetSystemInstanceList', instance_id => $local_instance_id, return_output => 1)); - my $instance_id = (split(', ', $instance_data[0]))[1]; - $instance_id = sprintf("%02d", $instance_id); - - return ($instance_id); -} - =head2 get_instance_profile_path $self->get_instance_profile_path(instance_type=>$instance_type, instance_id=$instance_id); diff --git a/lib/sles4sap/sapcontrol.pm b/lib/sles4sap/sapcontrol.pm new file mode 100644 index 000000000000..60cd43879434 --- /dev/null +++ b/lib/sles4sap/sapcontrol.pm @@ -0,0 +1,242 @@ +# SUSE's openQA tests +# +# Copyright SUSE LLC +# SPDX-License-Identifier: FSFAP +# Maintainer: QE-SAP + +package sles4sap::sapcontrol; + +use strict; +use warnings; +use testapi; +use Exporter qw(import); +use Carp qw(croak); +use hacluster qw(script_output_retry_check); + +our @EXPORT = qw( + sapcontrol + sapcontrol_process_check + sap_show_status_info + get_remote_instance_number +); + +=head1 SYNOPSIS + +Package containing functions which interact or are related to C execution. + +=cut + +=head2 sapcontrol + + sapcontrol(instance_id=>'00', + webmethod=>'GetProcessList', + sidadm=>'pooadm', + [additional_args=>'someargument', + remote_execution=>$remote_execution]); + +Executes sapcontrol webmethod for instance specified in arguments and returns exit code received from command. +Allows remote execution of webmethods between instances, however not all webmethods are possible to execute in that manner. +Function expects to be executed from an authorized user (sidadm or root). + +Sapcontrol return codes: + + RC 0 = webmethod call was successful + RC 1 = webmethod call failed + RC 2 = last webmethod call in progress (processes are starting/stopping) + RC 3 = all processes GREEN + RC 4 = all processes GREY (stopped) + +=over + +=item * B 2 digit instance number + +=item * B webmethod name to be executed (Ex: Stop, GetProcessList, ...) + +=item * B additional arguments to be appended at the end of command + +=item * B returns output instead of RC + +=item * B hostname of the target instance for remote execution. Local execution does not need this. + +=item * B Password for sidadm user. Only required for remote execution. + +=item * B sidadm user. Only required for remote execution. + +=back +=cut + +sub sapcontrol { + my (%args) = @_; + my $current_user = script_output_retry_check(cmd => 'whoami', sleep => 2, regex_string => "^root\$"); + + croak "Mandatory argument 'webmethod' not specified" unless $args{webmethod}; + croak "Mandatory argument 'instance_id' not specified" unless $args{instance_id}; + + my $cmd = join(' ', 'sapcontrol', '-nr', $args{instance_id}); + # variables below allow sapcontrol to run under root + my $sapcontrol_path_root = '/usr/sap/hostctrl/exe'; + my $root_env = "LD_LIBRARY_PATH=$sapcontrol_path_root:\$LD_LIBRARY_PATH"; + $cmd = $current_user eq 'root' ? "$root_env $sapcontrol_path_root/$cmd" : $cmd; + + if ($args{remote_hostname}) { + croak "Mandatory argument 'sidadm' not specified" unless $args{sidadm}; + croak "Mandatory argument 'sidadm_password' not specified" unless $args{sidadm_password}; + $cmd = join(' ', $cmd, '-host', $args{remote_hostname}, '-user', $args{sidadm}, $args{sidadm_password}); + } + + $cmd = join(' ', $cmd, '-function', $args{webmethod}); + $cmd .= " $args{additional_args}" if $args{additional_args}; + my $result = $args{return_output} ? script_output($cmd, proceed_on_failure => 1) : script_run($cmd); + + return ($result); +} + + +=head2 sap_show_status_info + + sap_show_status_info(cluster=>1, netweaver=>1); + +Prints output for standard set of commands to show info about system in various stages of the test for troubleshooting. +It is possible to activate or deactivate various output sections by named args: + +=over + +=item * B - Shows cluster related outputs + +=item * B - Shows netweaver related outputs + +=back +=cut + +sub sap_show_status_info { + my (%args) = @_; + my $cluster = $args{cluster}; + my $netweaver = $args{netweaver}; + my $instance_id = defined($netweaver) ? $args{instance_id} : get_required_var('INSTANCE_ID'); + my @output; + + # Netweaver info + if (defined($netweaver)) { + push(@output, "\n//// NETWEAVER ///"); + push(@output, "\n### SAPCONTROL PROCESS LIST ###"); + push(@output, sapcontrol(instance_id => $instance_id, webmethod => 'GetProcessList', return_output => 1)); + push(@output, "\n### SAPCONTROL SYSTEM INSTANCE LIST ###"); + push(@output, sapcontrol(instance_id => $instance_id, webmethod => 'GetSystemInstanceList', return_output => 1)); + } + + # Cluster info + if (defined($cluster)) { + push(@output, "\n//// CLUSTER ///"); + push(@output, "\n### CLUSTER STATUS ###"); + push(@output, script_output('PAGER=/usr/bin/cat crm status')); + } + record_info('Status', join("\n", @output)); +} + +=head2 sapcontrol_process_check + + sapcontrol_process_check(expected_state=>expected_state, + [instance_id=>$instance_id, + loop_sleep=>$loop_sleep, + timeout=>$timeout, + wait_for_state=>$wait_for_state]); + +Runs "sapcontrol -nr -function GetProcessList" via SIDadm and compares RC against expected state. +Croaks if state is not correct. + +Expected return codes are: + + RC 0 = webmethod call was successfull + RC 1 = webmethod call failed (This includes NIECONN_REFUSED status) + RC 2 = last webmethod call in progress (processes are starting/stopping) + RC 3 = all processes GREEN + RC 4 = all processes GREY (stopped) + +=over + +=item * B State that is expected (failed, started, stopped) + +=item * B Instance number - two digit number + +=item * B sleep time between checks - only used if 'wait_for_state' is true + +=item * B timeout for waiting for target state, after which function croaks + +=item * B If set to true, function will wait for expected state until success or timeout + +=back +=cut + +sub sapcontrol_process_check { + my (%args) = @_; + my $instance_id = $args{instance_id} // get_required_var('INSTANCE_ID'); + my $expected_state = $args{expected_state}; + my $loop_sleep = $args{loop_sleep} // 5; + my $timeout = $args{timeout} // bmwqemu::scale_timeout(120); + my $wait_for_state = $args{wait_for_state} // 0; + my %state_to_rc = ( + failed => '1', # After stopping service (ServiceStop method) sapcontrol returns RC1 + started => '3', + stopped => '4' + ); + + croak "Argument 'expected state' undefined" unless defined($expected_state); + + my @allowed_state_values = keys(%state_to_rc); + $expected_state = lc $expected_state; + croak "Value '$expected_state' for argument 'expected state' not supported. Allowed values: '@allowed_state_values'" + unless (grep(/^$expected_state$/, @allowed_state_values)); + + my $rc = sapcontrol(instance_id => $instance_id, webmethod => 'GetProcessList'); + my $start_time = time; + + while ($rc ne $state_to_rc{$expected_state}) { + last unless $wait_for_state; + $rc = sapcontrol(instance_id => $instance_id, webmethod => 'GetProcessList'); + croak "Timeout while waiting for expected state: $expected_state" if (time - $start_time > $timeout); + sleep $loop_sleep; + } + + if ($state_to_rc{$expected_state} ne $rc) { + sap_show_status_info(netweaver => 1, instance_id => $instance_id); + croak "Processes are not '$expected_state'"; + } + + return $expected_state; +} + +=head2 get_remote_instance_number + + get_instance_number(instance_type=>$instance_type); + +Finds instance number from remote instance using sapcontrol "GetSystemInstanceList" webmethod. +Local system instance number is required to execute sapcontrol though. + +=over + +=item * B Instance type (ASCS, ERS) - this can be expanded to other instances + +=back +=cut + +sub get_remote_instance_number { + my (%args) = @_; + my $local_instance_id = get_required_var('INSTANCE_ID'); + + croak "Missing mandatory argument 'instance_type'." unless $args{instance_type}; + croak "Function is not yet implemented for instance type: $args{instance_type}" unless + grep /$args{instance_type}/, ('ASCS', 'ERS'); + + # This needs to be expanded for PAS and AAS + my %instance_type_features = ( + ASCS => 'MESSAGESERVER', + ERS => 'ENQREP' + ); + + my @instance_data = grep /$instance_type_features{$args{instance_type}}/, + split('\n', sapcontrol(webmethod => 'GetSystemInstanceList', instance_id => $local_instance_id, return_output => 1)); + my $instance_id = (split(', ', $instance_data[0]))[1]; + $instance_id = sprintf("%02d", $instance_id); + + return ($instance_id); +} diff --git a/t/17_sles4sap.t b/t/17_sles4sap.t index 65488282b266..52c2e732617a 100644 --- a/t/17_sles4sap.t +++ b/t/17_sles4sap.t @@ -172,47 +172,6 @@ subtest '[netweaver_installation_data] Test returned values - common variables' undef_vars(); }; -subtest '[sapcontrol_process_check] Test expected failures.' => sub { - my $mockObject = sles4sap->new(); - my $sles4sap = Test::MockModule->new('sles4sap', no_auto => 1); - $sles4sap->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); - $sles4sap->redefine(sapcontrol => sub { return '3'; }); - my %argument_values = ( - sidadm => 'sidadm', instance_id => '00', expected_state => 'started'); - - $argument_values{expected_state} = undef; - dies_ok { $mockObject->sapcontrol_process_check(%argument_values) } "Expected failure with missing argument: 'expected_state'"; - $argument_values{expected_state} = 'started'; - - foreach ('stoped', 'stated', 'sstopped', 'startedd', 'somethingweird', ' started ') { - my $orig_value = $argument_values{expected_state}; - $argument_values{expected_state} = $_; - dies_ok { $mockObject->sapcontrol_process_check(%argument_values) } "Fail with unsupported 'expected_state' value: \'$_'"; - $argument_values{expected_state} = $orig_value; - } - - $sles4sap->redefine(sapcontrol => sub { return '3' }); - $argument_values{expected_state} = 'stopped'; - dies_ok { $mockObject->sapcontrol_process_check(%argument_values) } 'Fail with services not stopped.'; - $sles4sap->redefine(sapcontrol => sub { return '4' }); - $argument_values{expected_state} = 'started'; - dies_ok { $mockObject->sapcontrol_process_check(%argument_values) } 'Fail with services not started.'; -}; - -subtest '[sapcontrol_process_check] Function PASS.' => sub { - my $mockObject = sles4sap->new(); - my $sles4sap = Test::MockModule->new('sles4sap', no_auto => 1); - $sles4sap->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); - my %argument_values = (instance_id => '00', expected_state => 'started'); - - $sles4sap->redefine(sapcontrol => sub { return '4' }); - $argument_values{expected_state} = 'stopped'; - is $mockObject->sapcontrol_process_check(%argument_values), 'stopped', 'Pass with services being stopped (RC4)'; - $sles4sap->redefine(sapcontrol => sub { return '3' }); - $argument_values{expected_state} = 'started'; - is $mockObject->sapcontrol_process_check(%argument_values), 'started', 'Pass with services being started (RC3)'; -}; - subtest '[share_hosts_entry] All args defined' => sub { my $mockObject = sles4sap->new(); my @calls; @@ -285,61 +244,6 @@ subtest '[get_sidadm]' => sub { undef_vars(); }; -subtest '[sapcontrol] Test expected failures' => sub { - my $mockObject = sles4sap->new(); - my $sles4sap = Test::MockModule->new('sles4sap', no_auto => 1); - $sles4sap->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); - $sles4sap->redefine(get_sidadm => sub { return 'abcadm'; }); - my %arguments = (instance_id => '00', webmethod => 'GoOverThere'); - - $sles4sap->redefine(script_output_retry_check => sub { return 'abcadm'; }); - $sles4sap->redefine(script_run => sub { return '0'; }); - $arguments{webmethod} = ''; - dies_ok { $mockObject->sapcontrol(%arguments) } 'Fail without specifying webmethod'; - $arguments{webmethod} = 'GoOverThere'; - - $arguments{instance_id} = ''; - dies_ok { $mockObject->sapcontrol(%arguments) } 'Fail without specifying instance_id'; - $arguments{instance_id} = '00'; - - $sles4sap->redefine(script_output_retry_check => sub { return 'ninasharp'; }); - dies_ok { $mockObject->sapcontrol(%arguments) } 'Fail if running under incorrect user'; - $sles4sap->redefine(script_output_retry_check => sub { return 'abcadm'; }); - - $arguments{remote_hostname} = 'charlie'; - dies_ok { $mockObject->sapcontrol(%arguments) } 'Remote execution fail without sidadm password'; -}; - -subtest '[sapcontrol] Test using correct values' => sub { - my $mockObject = sles4sap->new(); - my $sles4sap = Test::MockModule->new('sles4sap', no_auto => 1); - my @calls; - $sles4sap->redefine(script_output => sub { return 'command output' }); - $sles4sap->redefine(script_output_retry_check => sub { return 'abcadm'; }); - $sles4sap->redefine(script_run => sub { push(@calls, @_); return '0'; }); - $sles4sap->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); - $sles4sap->redefine(get_sidadm => sub { return 'abcadm'; }); - - my %arguments = (instance_id => '00', webmethod => 'GoOverThere'); - - is $mockObject->sapcontrol(%arguments), '0', 'Return correct RC'; - is $calls[0], 'sapcontrol -nr 00 -function GoOverThere', 'Execute correct command'; - $arguments{additional_args} = 'And Return Back'; - $mockObject->sapcontrol(%arguments); - is $calls[1], 'sapcontrol -nr 00 -function GoOverThere And Return Back', 'Execute correct command with additional args'; - $arguments{additional_args} = ''; - - $arguments{return_output} = 1; - is $mockObject->sapcontrol(%arguments), 'command output', 'Return command output instead of RC'; - $arguments{return_output} = 0; - - $arguments{remote_hostname} = 'charlie'; - $arguments{sidadm_password} = 'Fr@ncis'; - $mockObject->sapcontrol(%arguments); - is $calls[2], 'sapcontrol -nr 00 -host charlie -user abcadm Fr@ncis -function GoOverThere', - 'Execute correct command for remote execution'; -}; - subtest '[get_instance_profile_path]' => sub { my $mockObject = sles4sap->new(); my $sles4sap = Test::MockModule->new('sles4sap', no_auto => 1); @@ -354,24 +258,4 @@ subtest '[get_instance_profile_path]' => sub { undef_vars(); }; -subtest '[get_remote_instance_number]' => sub { - my $mockObject = sles4sap->new(); - my $sles4sap = Test::MockModule->new('sles4sap', no_auto => 1); - $sles4sap->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); - set_var('INSTANCE_ID', '00'); - my $sapcontrol_out = ' -30.11.2023 07:15:42 -GetSystemInstanceList -OK -hostname, instanceNr, httpPort, httpsPort, startPriority, features, dispstatus -sapen2er, 1, 50113, 50114, 0.5, ENQREP, GREEN -sapen2as, 0, 50013, 50014, 1, MESSAGESERVER|ENQUE, GREEN'; - $sles4sap->redefine(sapcontrol => sub { return $sapcontrol_out }); - - is $mockObject->get_remote_instance_number(instance_type => 'ASCS'), '00', 'Return correct ASCS instance number.'; - is $mockObject->get_remote_instance_number(instance_type => 'ERS'), '01', 'Return correct ERS instance number.'; - - undef_vars(); -}; - done_testing; diff --git a/t/30_sapcontrol.t b/t/30_sapcontrol.t new file mode 100644 index 000000000000..bc7d70e36b7a --- /dev/null +++ b/t/30_sapcontrol.t @@ -0,0 +1,123 @@ +use strict; +use warnings; +use Test::More; +use Test::Exception; +use Test::Warnings; +use Test::MockModule; +use testapi; +use sles4sap::sapcontrol; + +sub undef_vars { + set_var($_, undef) for qw( + INSTANCE_TYPE + INSTANCE_SID + INSTANCE_ID); +} + +subtest '[sapcontrol] Test expected failures' => sub { + my $sapcontrol = Test::MockModule->new('sles4sap::sapcontrol', no_auto => 1); + $sapcontrol->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + my %arguments = (instance_id => '00', webmethod => 'GoOverThere', sidadm => 'abcadm'); + + $sapcontrol->redefine(script_output_retry_check => sub { return 'abcadm'; }); + $sapcontrol->redefine(script_run => sub { return '0'; }); + $arguments{webmethod} = ''; + dies_ok { sapcontrol(%arguments) } 'Fail without specifying webmethod'; + $arguments{webmethod} = 'GoOverThere'; + + $arguments{instance_id} = ''; + dies_ok { sapcontrol(%arguments) } 'Fail without specifying instance_id'; + $arguments{instance_id} = '00'; + + $sapcontrol->redefine(script_output_retry_check => sub { return 'abcadm'; }); + $arguments{remote_hostname} = 'charlie'; + dies_ok { sapcontrol(%arguments) } 'Remote execution fail without sidadm password'; +}; + +subtest '[sapcontrol] Test using correct values' => sub { + my $sapcontrol = Test::MockModule->new('sles4sap::sapcontrol', no_auto => 1); + my @calls; + $sapcontrol->redefine(script_output => sub { return 'command output' }); + $sapcontrol->redefine(script_output_retry_check => sub { return 'abcadm'; }); + $sapcontrol->redefine(script_run => sub { push(@calls, @_); return '0'; }); + $sapcontrol->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + + my %arguments = (instance_id => '00', webmethod => 'GoOverThere', sidadm => 'abcadm'); + + is sapcontrol(%arguments), '0', 'Return correct RC'; + is $calls[0], 'sapcontrol -nr 00 -function GoOverThere', 'Execute correct command'; + $arguments{additional_args} = 'And Return Back'; + sapcontrol(%arguments); + is $calls[1], 'sapcontrol -nr 00 -function GoOverThere And Return Back', 'Execute correct command with additional args'; + $arguments{additional_args} = ''; + + $arguments{return_output} = 1; + is sapcontrol(%arguments), 'command output', 'Return command output instead of RC'; + $arguments{return_output} = 0; + + $arguments{remote_hostname} = 'charlie'; + $arguments{sidadm_password} = 'Fr@ncis'; + sapcontrol(%arguments); + is $calls[2], 'sapcontrol -nr 00 -host charlie -user abcadm Fr@ncis -function GoOverThere', + 'Execute correct command for remote execution'; +}; + +subtest '[sapcontrol_process_check] Test expected failures.' => sub { + my $sapcontrol = Test::MockModule->new('sles4sap::sapcontrol', no_auto => 1); + $sapcontrol->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + $sapcontrol->redefine(sapcontrol => sub { return '3'; }); + my %argument_values = ( + sidadm => 'sidadm', instance_id => '00', expected_state => 'started'); + + $argument_values{expected_state} = undef; + dies_ok { sapcontrol_process_check(%argument_values) } "Expected failure with missing argument: 'expected_state'"; + $argument_values{expected_state} = 'started'; + + foreach ('stoped', 'stated', 'sstopped', 'startedd', 'somethingweird', ' started ') { + my $orig_value = $argument_values{expected_state}; + $argument_values{expected_state} = $_; + dies_ok { sapcontrol_process_check(%argument_values) } "Fail with unsupported 'expected_state' value: \'$_'"; + $argument_values{expected_state} = $orig_value; + } + + $sapcontrol->redefine(sapcontrol => sub { return '3' }); + $argument_values{expected_state} = 'stopped'; + dies_ok { sapcontrol_process_check(%argument_values) } 'Fail with services not stopped.'; + $sapcontrol->redefine(sapcontrol => sub { return '4' }); + $argument_values{expected_state} = 'started'; + dies_ok { sapcontrol_process_check(%argument_values) } 'Fail with services not started.'; +}; + +subtest '[sapcontrol_process_check] Function PASS.' => sub { + my $sapcontrol = Test::MockModule->new('sles4sap::sapcontrol', no_auto => 1); + $sapcontrol->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + my %argument_values = (instance_id => '00', expected_state => 'started'); + + $sapcontrol->redefine(sapcontrol => sub { return '4' }); + $argument_values{expected_state} = 'stopped'; + is sapcontrol_process_check(%argument_values), 'stopped', 'Pass with services being stopped (RC4)'; + $sapcontrol->redefine(sapcontrol => sub { return '3' }); + $argument_values{expected_state} = 'started'; + is sapcontrol_process_check(%argument_values), 'started', 'Pass with services being started (RC3)'; +}; + +subtest '[get_remote_instance_number]' => sub { + my $sapcontrol = Test::MockModule->new('sles4sap::sapcontrol', no_auto => 1); + $sapcontrol->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + set_var('INSTANCE_ID', '00'); + my $sapcontrol_out = ' +30.11.2023 07:15:42 +GetSystemInstanceList +OK +hostname, instanceNr, httpPort, httpsPort, startPriority, features, dispstatus +sapen2er, 1, 50113, 50114, 0.5, ENQREP, GREEN +sapen2as, 0, 50013, 50014, 1, MESSAGESERVER|ENQUE, GREEN'; + $sapcontrol->redefine(sapcontrol => sub { return $sapcontrol_out }); + + is get_remote_instance_number(instance_type => 'ASCS'), '00', 'Return correct ASCS instance number.'; + is get_remote_instance_number(instance_type => 'ERS'), '01', 'Return correct ERS instance number.'; + + undef_vars(); +}; + +done_testing; diff --git a/tests/sles4sap/ensa/ensa2_cluster_connector_setup.pm b/tests/sles4sap/ensa/ensa2_cluster_connector_setup.pm index 91b7a5538de2..71b2b47e818a 100644 --- a/tests/sles4sap/ensa/ensa2_cluster_connector_setup.pm +++ b/tests/sles4sap/ensa/ensa2_cluster_connector_setup.pm @@ -16,6 +16,7 @@ use testapi; use hacluster; use serial_terminal qw(select_serial_terminal); use utils qw(file_content_replace); +use sles4sap::sapcontrol; use lockapi; sub run { @@ -32,7 +33,7 @@ sub run { if ($instance_type eq 'ASCS') { my $profile_path_ascs = $self->get_instance_profile_path(instance_id => $instance_id, instance_type => 'ASCS'); - my $instance_id_ers = $self->get_remote_instance_number(instance_type => 'ERS'); + my $instance_id_ers = get_remote_instance_number(instance_type => 'ERS'); my $profile_path_ers = $self->get_instance_profile_path(instance_type => 'ERS', instance_id => $instance_id_ers); record_info('SAP params', 'Changing SAP instance parameters required for cluster connector'); @@ -55,18 +56,17 @@ sub run { # Restart instances to apply parameter values record_info('SAP restart', 'Restarting ASCS and ERS to apply parameters'); - $self->sapcontrol(webmethod => 'StopService', instance_id => $instance_id); - $self->sapcontrol_process_check(expected_state => 'failed', wait_for_state => 1); # After stop service sapcontrol returns RC1 (NIECONN_REFUSED) - $self->sapcontrol(webmethod => 'StartService', additional_args => $sap_sid, instance_id => $instance_id); - $self->sapcontrol_process_check(expected_state => 'started', wait_for_state => 1); + sapcontrol(webmethod => 'StopService', sidadm => $sidadm, instance_id => $instance_id); + sapcontrol_process_check(expected_state => 'failed', wait_for_state => 1); # After stop service sapcontrol returns RC1 (NIECONN_REFUSED) + sapcontrol(webmethod => 'StartService', sidadm => $sidadm, additional_args => $sap_sid, instance_id => $instance_id); + sapcontrol_process_check(expected_state => 'started', wait_for_state => 1); assert_script_run("crm configure property maintenance-mode='false'"); crm_wait_for_maintenance(target_state => 'false'); # Ensure resource groups are started in correct place (physical hostname) crm_check_resource_location(resource => "grp_$sap_sid\_$instance_type$instance_id", wait_for_target => $physical_hostname); - $self->sap_show_status_info(cluster => 1, netweaver => 1, - instance_id => $instance_id); + sap_show_status_info(cluster => 1, netweaver => 1, instance_id => $instance_id); } 1; diff --git a/tests/sles4sap/ensa/ensa2_cluster_setup.pm b/tests/sles4sap/ensa/ensa2_cluster_setup.pm index adff39bdc25d..48b587985ff1 100644 --- a/tests/sles4sap/ensa/ensa2_cluster_setup.pm +++ b/tests/sles4sap/ensa/ensa2_cluster_setup.pm @@ -12,6 +12,7 @@ use testapi; use serial_terminal qw(select_serial_terminal); use utils qw(file_content_replace); use hacluster qw(wait_until_resources_started); +use sles4sap::sapcontrol; use lockapi; sub run { @@ -57,8 +58,7 @@ sub run { barrier_wait('ENSA_CLUSTER_SETUP'); } wait_until_resources_started(); - $self->sap_show_status_info(cluster => 1, netweaver => 1, - instance_id => $install_data->{instances}{$instance_type}{instance_id}); + sap_show_status_info(cluster => 1, netweaver => 1, instance_id => $install_data->{instances}{$instance_type}{instance_id}); } 1; diff --git a/tests/sles4sap/ensa/ensa2_web_methods_checks.pm b/tests/sles4sap/ensa/ensa2_web_methods_checks.pm index f89773289e89..25982f231266 100644 --- a/tests/sles4sap/ensa/ensa2_web_methods_checks.pm +++ b/tests/sles4sap/ensa/ensa2_web_methods_checks.pm @@ -14,24 +14,26 @@ use testapi; use hacluster; use lockapi; use serial_terminal qw(select_serial_terminal); -use version_utils 'is_sle'; +use version_utils qw(is_sle); +use sles4sap::sapcontrol; sub webmethod_checks { - my ($self, $instance_id) = @_; + my ($self, $instance_id,) = @_; my $outputs; my $looptime = 300; # General status will help with troubleshooting - $self->sap_show_status_info(cluster => 1, netweaver => 1, instance_id => $instance_id); + my $sidadm = $self->get_sidadm(); + sap_show_status_info(cluster => 1, netweaver => 1, instance_id => $instance_id); record_info('ENSA check', "Executing 'HACheckConfig' and 'HACheckFailoverConfig'"); - while ($outputs = $self->sapcontrol(webmethod => 'HACheckConfig', instance_id => $instance_id, return_output => 1)) { + while ($outputs = sapcontrol(webmethod => 'HACheckConfig', instance_id => $instance_id, sidadm => $sidadm, return_output => 1)) { last unless ($outputs =~ /ERROR/); record_info("ERROR found in HACheckConfig: $outputs", "sleep 30s and try again"); sleep 30; $looptime -= 30; last if ($looptime <= 0); } - $self->sapcontrol(webmethod => 'HACheckFailoverConfig', instance_id => $instance_id); + sapcontrol(webmethod => 'HACheckFailoverConfig', instance_id => $instance_id, sidadm => $sidadm); } sub run { @@ -41,7 +43,8 @@ sub run { my $instance_type_original = get_required_var('INSTANCE_TYPE'); my $instance_type_remote = $instance_type_original eq 'ASCS' ? 'ERS' : 'ASCS'; my $physical_hostname = get_required_var('HOSTNAME'); - my $instance_id_remote = $self->get_remote_instance_number(instance_type => $instance_type_remote); + my $instance_id_remote = get_remote_instance_number(instance_type => $instance_type_remote); + my $sidadm = $self->get_sidadm(); select_serial_terminal; @@ -56,7 +59,7 @@ sub run { # Execute failover from ASCS instance if ($instance_type eq 'ASCS') { record_info('Failover', "Executing 'HAFailoverToNode'. Failover from $physical_hostname to remote site"); - $self->sapcontrol(webmethod => 'HAFailoverToNode', instance_id => $instance_id, additional_args => "\"\""); + sapcontrol(webmethod => 'HAFailoverToNode', instance_id => $instance_id, additional_args => "\"\""); } # After failover, instance type, ID etc is switched. @@ -76,7 +79,8 @@ sub run { record_info "sleep 300s for 12-SP5"; } record_info('Failover', "Executing 'HAFailoverToNode'. Failover from $physical_hostname to remote site"); - $self->sapcontrol(webmethod => 'HAFailoverToNode', instance_id => $instance_id, additional_args => "\"\""); + sapcontrol(webmethod => 'HAFailoverToNode', instance_id => $instance_id, sidadm => $sidadm, + additional_args => "\"\""); } # After failover, instance type, ID etc is switched. diff --git a/tests/sles4sap/ensa/netweaver_swpm_installation.pm b/tests/sles4sap/ensa/netweaver_swpm_installation.pm index 3ae30d71c0e6..f4988123fabd 100644 --- a/tests/sles4sap/ensa/netweaver_swpm_installation.pm +++ b/tests/sles4sap/ensa/netweaver_swpm_installation.pm @@ -14,6 +14,7 @@ use lockapi; use hacluster; use strict; use warnings; +use sles4sap::sapcontrol; sub raise_barriers { my (%args) = @_; @@ -92,7 +93,7 @@ sub run { record_info('SAPINST EXEC', "Executing sapinst command:\n$swpm_command"); assert_script_run($swpm_command, timeout => 600); - $self->sapcontrol_process_check(sidadm => $nw_install_data->{sidadm}, + sapcontrol_process_check(sidadm => $nw_install_data->{sidadm}, instance_id => $instance_data->{instance_id}, expected_state => 'started'); @@ -100,7 +101,7 @@ sub run { release_barrier(instance_type => $instance_type, instances => \@instances); # sync all nodes after installation done and show status info on SAP instances barrier_wait('SAPINST_INSTALLATION_FINISHED'); - $self->sap_show_status_info(netweaver => 1, instance_id => $instance_data->{instance_id}) + sap_show_status_info(netweaver => 1, instance_id => $instance_data->{instance_id}) if grep($instance_type, ('ERS', 'ASCS', 'PAS', 'AAS')); }