From ae41ba9a91d3bf0651b3719104874ba8310ce23e Mon Sep 17 00:00:00 2001 From: Carmine Di Monaco Date: Tue, 20 Jun 2023 11:12:19 +0200 Subject: [PATCH] Sap system restore domain --- .../sap_system/events/sap_system_restored.ex | 17 ++ lib/trento/domain/sap_system/sap_system.ex | 55 ++++ test/support/factory.ex | 19 ++ .../domain/sap_system/sap_system_test.exs | 270 ++++++++++++++++++ 4 files changed, 361 insertions(+) create mode 100644 lib/trento/domain/sap_system/events/sap_system_restored.ex diff --git a/lib/trento/domain/sap_system/events/sap_system_restored.ex b/lib/trento/domain/sap_system/events/sap_system_restored.ex new file mode 100644 index 0000000000..581f016e09 --- /dev/null +++ b/lib/trento/domain/sap_system/events/sap_system_restored.ex @@ -0,0 +1,17 @@ +defmodule Trento.Domain.Events.SapSystemRestored do + @moduledoc """ + This event is emitted when a sap system is restored. + """ + + use Trento.Event + + require Trento.Domain.Enums.Health, as: Health + + defevent do + field :sap_system_id, Ecto.UUID + field :sid, :string + field :tenant, :string + field :db_host, :string + field :health, Ecto.Enum, values: Health.values() + end +end diff --git a/lib/trento/domain/sap_system/sap_system.ex b/lib/trento/domain/sap_system/sap_system.ex index 6556942685..8fb2a979dd 100644 --- a/lib/trento/domain/sap_system/sap_system.ex +++ b/lib/trento/domain/sap_system/sap_system.ex @@ -79,6 +79,7 @@ defmodule Trento.Domain.SapSystem do SapSystemDeregistered, SapSystemHealthChanged, SapSystemRegistered, + SapSystemRestored, SapSystemRolledUp, SapSystemRollUpRequested, SapSystemTombstoned, @@ -238,6 +239,27 @@ defmodule Trento.Domain.SapSystem do |> Multi.execute(&maybe_emit_sap_system_health_changed_event/1) end + # Restore sap system + # Same registration rules + def execute( + %SapSystem{deregistered_at: deregistered_at} = sap_system, + %RegisterApplicationInstance{} = instance + ) + when not is_nil(deregistered_at) do + sap_system + |> Multi.new() + |> Multi.execute(fn sap_system -> + emit_application_instance_registered_or_application_instance_health_changed( + sap_system, + instance + ) + end) + |> Multi.execute(fn sap_system -> + maybe_emit_sap_system_restored_event(sap_system, instance) + end) + |> Multi.execute(&maybe_emit_sap_system_health_changed_event/1) + end + # SAP system not registered, application already present # If the instance is not one of MESSAGESERVER or ABAP we discard. # Otherwise if the instance we want register together with already present instances @@ -668,6 +690,18 @@ defmodule Trento.Domain.SapSystem do } end + def apply(%SapSystem{} = sap_system, %SapSystemRestored{ + sid: sid, + health: health + }) do + %SapSystem{ + sap_system + | sid: sid, + health: health, + deregistered_at: nil + } + end + def apply(%SapSystem{} = sap_system, %SapSystemTombstoned{}), do: sap_system defp maybe_emit_database_instance_registered_event( @@ -848,6 +882,27 @@ defmodule Trento.Domain.SapSystem do end end + defp maybe_emit_sap_system_restored_event( + %SapSystem{application: %Application{instances: instances}}, + %RegisterApplicationInstance{ + sap_system_id: sap_system_id, + sid: sid, + tenant: tenant, + db_host: db_host, + health: health + } + ) do + if instances_have_abap?(instances) and instances_have_messageserver?(instances) do + %SapSystemRestored{ + db_host: db_host, + health: health, + sap_system_id: sap_system_id, + sid: sid, + tenant: tenant + } + end + end + defp maybe_emit_sap_system_registered_or_updated_event( %SapSystem{sid: nil, application: %Application{instances: instances}}, %RegisterApplicationInstance{ diff --git a/test/support/factory.ex b/test/support/factory.ex index 9691fe54d1..973bd29004 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -21,6 +21,7 @@ defmodule Trento.Factory do } alias Trento.Domain.Events.{ + ApplicationInstanceDeregistered, ApplicationInstanceRegistered, ClusterDeregistered, ClusterRegistered, @@ -29,6 +30,7 @@ defmodule Trento.Factory do DatabaseInstanceDeregistered, DatabaseInstanceRegistered, DatabaseRegistered, + DatabaseRestored, HostAddedToCluster, HostDetailsUpdated, HostRegistered, @@ -267,6 +269,14 @@ defmodule Trento.Factory do }) end + def database_restored_event_factory do + DatabaseRestored.new!(%{ + sap_system_id: Faker.UUID.v4(), + sid: Faker.UUID.v4(), + health: Health.passing() + }) + end + def deregister_database_instance_command_factory do DeregisterDatabaseInstance.new!(%{ sap_system_id: Faker.UUID.v4(), @@ -298,6 +308,15 @@ defmodule Trento.Factory do } end + def application_instance_deregistered_event_factory do + ApplicationInstanceDeregistered.new!(%{ + sap_system_id: Faker.UUID.v4(), + deregistered_at: DateTime.utc_now(), + instance_number: "00", + host_id: Faker.UUID.v4() + }) + end + def deregister_application_instance_command_factory do DeregisterApplicationInstance.new!(%{ sap_system_id: Faker.UUID.v4(), diff --git a/test/trento/domain/sap_system/sap_system_test.exs b/test/trento/domain/sap_system/sap_system_test.exs index 312abe32b0..3f5d7b5b5e 100644 --- a/test/trento/domain/sap_system/sap_system_test.exs +++ b/test/trento/domain/sap_system/sap_system_test.exs @@ -28,6 +28,7 @@ defmodule Trento.SapSystemTest do SapSystemDeregistered, SapSystemHealthChanged, SapSystemRegistered, + SapSystemRestored, SapSystemRolledUp, SapSystemRollUpRequested, SapSystemTombstoned, @@ -2352,6 +2353,275 @@ defmodule Trento.SapSystemTest do ) end + test "should not restore a sap system when no abap/messageserver instances are present" do + sap_system_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + application_sid = fake_sid() + + message_server_host_id = UUID.uuid4() + message_server_instance_number = "00" + abap_host_id = UUID.uuid4() + abap_instance_number = "01" + + initial_events = [ + build( + :database_registered_event, + sap_system_id: sap_system_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: sap_system_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: sap_system_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build( + :application_instance_registered_event, + sap_system_id: sap_system_id, + features: "MESSAGESERVER|ENQUE", + host_id: message_server_host_id, + instance_number: message_server_instance_number, + sid: application_sid + ), + build( + :application_instance_registered_event, + sap_system_id: sap_system_id, + features: "ABAP|GATEWAY|ICMAN|IGS", + host_id: abap_host_id, + instance_number: abap_instance_number, + sid: application_sid + ), + build( + :sap_system_registered_event, + sap_system_id: sap_system_id, + sid: application_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: sap_system_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: sap_system_id, + deregistered_at: deregistered_at + ), + build(:sap_system_deregistered_event, + sap_system_id: sap_system_id, + deregistered_at: deregistered_at + ), + build(:application_instance_deregistered_event, + sap_system_id: sap_system_id, + deregistered_at: deregistered_at, + instance_number: message_server_instance_number, + host_id: message_server_host_id + ), + build(:database_instance_registered_event, + system_replication: "Primary", + sid: db_sid, + sap_system_id: sap_system_id + ), + build(:database_restored_event, + sap_system_id: sap_system_id, + sid: db_sid + ) + ] + + command = + build( + :register_application_instance_command, + sap_system_id: sap_system_id, + sid: application_sid, + db_host: primary_database_host_id, + features: "IGS" + ) + + assert_events_and_state( + initial_events, + command, + [ + %ApplicationInstanceRegistered{ + sap_system_id: sap_system_id, + sid: application_sid, + host_id: command.host_id, + instance_number: command.instance_number, + instance_hostname: command.instance_hostname, + features: command.features, + http_port: command.http_port, + https_port: command.https_port, + start_priority: command.start_priority, + health: command.health + } + ], + fn sap_system -> + assert %SapSystem{ + deregistered_at: ^deregistered_at, + database: %Database{ + deregistered_at: nil, + sid: ^db_sid + } + } = sap_system + end + ) + end + + test "should restore a sap system when abap/messageserver instances are present" do + sap_system_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + application_sid = fake_sid() + + message_server_host_id = UUID.uuid4() + message_server_instance_number = "00" + abap_host_id = UUID.uuid4() + abap_instance_number = "01" + + initial_events = [ + build( + :database_registered_event, + sap_system_id: sap_system_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: sap_system_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: sap_system_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build( + :application_instance_registered_event, + sap_system_id: sap_system_id, + features: "MESSAGESERVER|ENQUE", + host_id: message_server_host_id, + instance_number: message_server_instance_number, + sid: application_sid + ), + build( + :application_instance_registered_event, + sap_system_id: sap_system_id, + features: "ABAP|GATEWAY|ICMAN|IGS", + host_id: abap_host_id, + instance_number: abap_instance_number, + sid: application_sid + ), + build( + :sap_system_registered_event, + sap_system_id: sap_system_id, + sid: application_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: sap_system_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: sap_system_id, + deregistered_at: deregistered_at + ), + build(:sap_system_deregistered_event, + sap_system_id: sap_system_id, + deregistered_at: deregistered_at + ), + build(:application_instance_deregistered_event, + sap_system_id: sap_system_id, + deregistered_at: deregistered_at, + instance_number: message_server_instance_number, + host_id: message_server_host_id + ), + build(:database_instance_registered_event, + system_replication: "Primary", + sid: db_sid, + sap_system_id: sap_system_id + ), + build(:database_restored_event, + sap_system_id: sap_system_id, + sid: db_sid + ) + ] + + command = + build( + :register_application_instance_command, + sap_system_id: sap_system_id, + sid: application_sid, + db_host: primary_database_host_id, + features: "MESSAGESERVER" + ) + + assert_events_and_state( + initial_events, + command, + [ + %ApplicationInstanceRegistered{ + sap_system_id: sap_system_id, + sid: application_sid, + host_id: command.host_id, + instance_number: command.instance_number, + instance_hostname: command.instance_hostname, + features: command.features, + http_port: command.http_port, + https_port: command.https_port, + start_priority: command.start_priority, + health: command.health + }, + %SapSystemRestored{ + sap_system_id: sap_system_id, + sid: application_sid, + tenant: command.tenant, + db_host: command.db_host, + health: command.health + } + ], + fn sap_system -> + assert %SapSystem{ + deregistered_at: nil, + database: %Database{ + deregistered_at: nil, + sid: ^db_sid + } + } = sap_system + end + ) + end + test "should reject all the commands except for the registration/instance deregistration ones, when the SAP system is deregistered" do sap_system_id = UUID.uuid4()