diff --git a/lib/sles4sap_publiccloud.pm b/lib/sles4sap_publiccloud.pm index ed01b55a0b02..eb1e60dacc62 100644 --- a/lib/sles4sap_publiccloud.pm +++ b/lib/sles4sap_publiccloud.pm @@ -199,18 +199,19 @@ sub sles4sap_cleanup { sub get_hana_topology { my ($self, %args) = @_; my @topology; - my $hostname = $args{hostname}; - my $cmd_out = $self->run_cmd(cmd => "SAPHanaSR-showAttr --format=script", quiet => 1); + my $cmd_out = $self->run_cmd(cmd => 'SAPHanaSR-showAttr --format=script', quiet => 1); record_info("cmd_out", $cmd_out); my @all_parameters = map { if (/^Hosts/) { s,Hosts/,,; s,",,g; $_ } else { () } } split("\n", $cmd_out); my @all_hosts = uniq map { (split("/", $_))[0] } @all_parameters; for my $host (@all_hosts) { + # Only takes parameter and value for lines about one specific host at time my %host_parameters = map { my ($node, $parameter, $value) = split(/[\/=]/, $_); - if ($host eq $node) { ($parameter, $value) } else { () } } @all_parameters; + if ($host eq $node) { ($parameter, $value) } else { () } } + @all_parameters; push(@topology, \%host_parameters); - if (defined($hostname) && $hostname eq $host) { + if (defined($args{hostname}) && $args{hostname} eq $host) { return \%host_parameters; } } @@ -352,25 +353,24 @@ sub cleanup_resource { sub check_takeover { my ($self) = @_; my $hostname = $self->{my_instance}->{instance_id}; - my $retry_count = 0; die("Database on the fenced node '$hostname' is not offline") if ($self->is_hana_database_online); die("System replication '$hostname' is not offline") if ($self->is_primary_node_online); + my $retry_count = 0; TAKEOVER_LOOP: while (1) { my $topology = $self->get_hana_topology(); $retry_count++; for my $entry (@$topology) { my %host_entry = %$entry; - my $sync_state = $host_entry{sync_state}; - my $takeover_host = $host_entry{vhost}; - - if ($takeover_host ne $hostname && $sync_state eq "PRIM") { - record_info("Takeover status:", "Takeover complete to node '$takeover_host'"); + die "Missing 'vhost' field in topology output" unless defined($host_entry{vhost}); + die "Missing 'sync_state' field in topology output" unless defined($host_entry{sync_state}); + if ($host_entry{vhost} ne $hostname && $host_entry{sync_state} eq "PRIM") { + record_info("Takeover status:", "Takeover complete to node '$host_entry{vhost}'"); last TAKEOVER_LOOP; } - sleep 30; } die "Test failed: takeover failed to complete." if ($retry_count > 40); + sleep 30; } return 1; diff --git a/t/12_sles4sap_publicccloud.t b/t/12_sles4sap_publicccloud.t index 5cab16e5a0e8..16a53d67b716 100644 --- a/t/12_sles4sap_publicccloud.t +++ b/t/12_sles4sap_publicccloud.t @@ -175,4 +175,214 @@ subtest '[is_primary_node_online]' => sub { is $res, 1, "System replication is online on primary node"; }; +subtest '[get_hana_topology]' => sub { + my $self = sles4sap_publiccloud->new(); + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(run_cmd => sub { + my ($self, %args) = @_; + push @calls, $args{cmd}; + my $res = <redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + + my $topology = $self->get_hana_topology(); + + note("\n --> " . join("\n --> ", @calls)); + my $num_of_hosts = 0; + for my $entry (@$topology) { + $num_of_hosts++; + my %host_entry = %$entry; + note("vhost: $host_entry{vhost}"); + like $host_entry{vhost}, qr/vmhana/, "Parsing is ok for field vhost"; + } + + ok $num_of_hosts eq 2; +}; + + +subtest '[get_hana_topology] for a specific node' => sub { + my $self = sles4sap_publiccloud->new(); + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(run_cmd => sub { + my ($self, %args) = @_; + push @calls, $args{cmd}; + my $res = <redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + + my $entry = $self->get_hana_topology(hostname => 'vmhana02'); + + note("\n --> " . join("\n --> ", @calls)); + my %host_entry = %$entry; + note("vhost: $host_entry{vhost}"); + like $host_entry{vhost}, qr/vmhana02/, "Parsing is ok for field vhost"; +}; + + +subtest '[get_hana_topology] bad output' => sub { + my $self = sles4sap_publiccloud->new(); + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(run_cmd => sub { + my ($self, %args) = @_; + push @calls, $args{cmd}; + my $res = <redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + + my $topology = $self->get_hana_topology(); + + note("\n --> " . join("\n --> ", @calls)); + ok scalar @$topology eq 0; +}; + + +subtest '[check_takeover]' => sub { + my $self = sles4sap_publiccloud->new(); + $self->{my_instance}->{instance_id} = 'Yondu'; + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(is_hana_database_online => sub { return 0 }); + $sles4sap_publiccloud->redefine(is_primary_node_online => sub { return 0 }); + $sles4sap_publiccloud->redefine(run_cmd => sub { + my ($self, %args) = @_; + push @calls, $args{cmd}; + my $res = <redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + + # Note how it pass at the first iteration because: + # - two nodes in the output are named vmhana01 and vmhana02 + # - none has the name of "current node" that is Yondu + # - at least one of them with name different from Yondu is in state PRIM + ok $self->check_takeover(); + note("\n --> " . join("\n --> ", @calls)); +}; + + +subtest '[check_takeover] fail in showAttr' => sub { + my $self = sles4sap_publiccloud->new(); + $self->{my_instance}->{instance_id} = 'Yondu'; + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(is_hana_database_online => sub { return 0 }); + $sles4sap_publiccloud->redefine(is_primary_node_online => sub { return 0 }); + $sles4sap_publiccloud->redefine(run_cmd => sub { + my ($self, %args) = @_; + push @calls, $args{cmd}; + my $res = <redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + dies_ok { $self->check_takeover() } "check_takeover fails if SAPHanaSR-showAttr keep give bad respose"; + note("\n --> " . join("\n --> ", @calls)); +}; + + +subtest '[check_takeover] missing fields in SAPHanaSR-showAttr' => sub { + my $self = sles4sap_publiccloud->new(); + $self->{my_instance}->{instance_id} = 'vmhana01'; + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(is_hana_database_online => sub { return 0 }); + $sles4sap_publiccloud->redefine(is_primary_node_online => sub { return 0 }); + my $showAttr; + $sles4sap_publiccloud->redefine(run_cmd => sub { + my ($self, %args) = @_; + push @calls, $args{cmd}; + return $showAttr; + }); + $sles4sap_publiccloud->redefine(record_info => sub { note(join(' ', 'RECORD_INFO -->', @_)); }); + + $showAttr = <check_takeover() } "check_takeover fails if sync_state is missing in SAPHanaSR-showAttr output"; + note("\n --> " . join("\n --> ", @calls)); + @calls = (); + + $showAttr = <check_takeover() } "check_takeover fails if vhost is missing in SAPHanaSR-showAttr output"; + note("\n --> " . join("\n --> ", @calls)); +}; + + +subtest '[check_takeover] fail if DB online' => sub { + my $self = sles4sap_publiccloud->new(); + $self->{my_instance}->{instance_id} = 'Yondu'; + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(is_hana_database_online => sub { return 1 }); + + dies_ok { $self->check_takeover() } "Takeover failed if sles4sap_publiccloud return 1"; +}; + + +subtest '[check_takeover] fail if primary online' => sub { + my $self = sles4sap_publiccloud->new(); + $self->{my_instance}->{instance_id} = 'Yondu'; + my $sles4sap_publiccloud = Test::MockModule->new('sles4sap_publiccloud', no_auto => 1); + my @calls; + $sles4sap_publiccloud->redefine(is_hana_database_online => sub { return 0 }); + $sles4sap_publiccloud->redefine(is_primary_node_online => sub { return 1 }); + + dies_ok { $self->check_takeover() } "Takeover failed if is_primary_node_online return 1"; +}; + + done_testing;