Skip to content

Commit

Permalink
Merge pull request #20887 from lpalovsky/create_sapcontrol_library
Browse files Browse the repository at this point in the history
Move sapcontrol functions into separate library
  • Loading branch information
lpalovsky authored Jan 3, 2025
2 parents 6370d1d + 1cfb40c commit 5cacdd3
Show file tree
Hide file tree
Showing 8 changed files with 389 additions and 347 deletions.
212 changes: 0 additions & 212 deletions lib/sles4sap.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
Expand Down Expand Up @@ -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<cluster> - Shows cluster related outputs
B<netweaver> - 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<instance_id> 2 digit instance number
B<webmethod> webmethod name to be executed (Ex: Stop, GetProcessList, ...)
B<additional_args> additional arguments to be appended at the end of command
B<return_output> returns output instead of RC
B<remote_hostname> hostname of the target instance for remote execution. Local execution does not need this.
B<sidadm_password> 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 <INST_NO> -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<expected_state> State that is expected (failed, started, stopped)
B<instance_id> Instance number - two digit number
B<loop_sleep> sleep time between checks - only used if 'wait_for_state' is true
B<timeout> timeout for waiting for target state, after which function croaks
B<wait_for_state> 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> 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);
Expand Down
Loading

0 comments on commit 5cacdd3

Please sign in to comment.