Skip to content

Commit

Permalink
Cluster registration also for nodes not DC (#1275)
Browse files Browse the repository at this point in the history
* Cluster registration process happens also when the discovered node is
not a DC

* Address docs and testing review feedbacks

* Removed useless tests from cluster_tests

* Add host to cluster when a message from a dc host arrives for a cluster

Co-Authored-By: Fabrizio Sestito <fabrizio.sestito@suse.com>

* Add register cluster host test when the host is and is not a DC

---------

Co-authored-by: Fabrizio Sestito <fabrizio.sestito@suse.com>
  • Loading branch information
CDimonaco and fabriziosestito authored Mar 27, 2023
1 parent 592dd56 commit 3c0a318
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 22 deletions.
55 changes: 45 additions & 10 deletions lib/trento/domain/cluster/cluster.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ defmodule Trento.Domain.Cluster do
SAP workloads.
Each deployed cluster is registered as a new aggregate entry, meaning that all the hosts belonging
to the same cluster are part of the same stream. A cluster is registered first time/details updated afterwards
only by cluster discovery messages coming from the **designated controller** node. Once a cluster is
registered other hosts can be added receiving discovery messages coming from other nodes. All the hosts
are listed in the `hosts` field.
to the same cluster are part of the same stream.
A new cluster is registered when a cluster discovery message from any of the nodes of the cluster is received.
The cluster details will be populated if the received discovery message is coming from the **designated controller** node.
Otherwise the cluster details are left as unknown, and filled once a message from the **designated controller** is received.
Once a cluster is registered, other hosts will be added when cluster discovery messages from them are received.
All the hosts are listed in the `hosts` field.
The cluster aggregate stores and updates information coming in the cluster discovery messages such as:
Expand Down Expand Up @@ -112,8 +118,8 @@ defmodule Trento.Domain.Cluster do

def execute(%Cluster{rolling_up: true}, _), do: {:error, :cluster_rolling_up}

# When a DC cluster node is registered for the first time, a cluster is registered
# and the host of the node is added to the cluster
# When a DC node is discovered, a cluster is registered and the host is added to the cluster.
# The cluster details are populated with the information coming from the DC node.
def execute(
%Cluster{cluster_id: nil},
%RegisterClusterHost{
Expand Down Expand Up @@ -149,10 +155,34 @@ defmodule Trento.Domain.Cluster do
]
end

# If no DC node was received yet, no cluster was registered.
def execute(%Cluster{cluster_id: nil}, %RegisterClusterHost{designated_controller: false}),
do: {:error, :cluster_not_found}
# When a non-DC node is discovered, a cluster is registered and the host is added to the cluster.
# The cluster details are left as unknown, and filled once a message from the DC node is received.
def execute(%Cluster{cluster_id: nil}, %RegisterClusterHost{
cluster_id: cluster_id,
name: name,
host_id: host_id,
designated_controller: false
}) do
[
%ClusterRegistered{
cluster_id: cluster_id,
name: name,
type: :unknown,
sid: nil,
provider: :unknown,
resources_number: nil,
hosts_number: nil,
details: nil,
health: :unknown
},
%HostAddedToCluster{
cluster_id: cluster_id,
host_id: host_id
}
]
end

# If the cluster is already registered, and the host was never discovered before, it is added to the cluster.
def execute(
%Cluster{} = cluster,
%RegisterClusterHost{
Expand All @@ -163,14 +193,19 @@ defmodule Trento.Domain.Cluster do
maybe_emit_host_added_to_cluster_event(cluster, host_id)
end

# When a DC node is discovered, if the cluster is already registered,
# the cluster details are updated with the information coming from the DC node.
# The cluster discovered health is updated based on the new details.
def execute(
%Cluster{} = cluster,
%RegisterClusterHost{
designated_controller: true
designated_controller: true,
host_id: host_id
} = command
) do
cluster
|> Multi.new()
|> Multi.execute(fn cluster -> maybe_emit_host_added_to_cluster_event(cluster, host_id) end)
|> Multi.execute(fn cluster -> maybe_emit_cluster_details_updated_event(cluster, command) end)
|> Multi.execute(fn cluster ->
maybe_emit_cluster_discovered_health_changed_event(cluster, command)
Expand Down
102 changes: 90 additions & 12 deletions test/trento/domain/cluster/cluster_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ defmodule Trento.ClusterTest do
require Trento.Domain.Enums.Health, as: Health

describe "cluster registration" do
test "should register a cluster and add the node host to the cluster if the node is a DC" do
test "should register a cluster with full details and add the node host to the cluster if the node is a DC" do
cluster_id = Faker.UUID.v4()
host_id = Faker.UUID.v4()
name = Faker.StarWars.character()
Expand Down Expand Up @@ -81,7 +81,51 @@ defmodule Trento.ClusterTest do
)
end

test "should add a host to the cluster" do
test "should register a cluster with unknown details when the cluster was not registered yet and a message from a non-DC is received" do
cluster_id = Faker.UUID.v4()
host_id = Faker.UUID.v4()
name = Faker.StarWars.character()

assert_events_and_state(
[],
RegisterClusterHost.new!(%{
cluster_id: cluster_id,
host_id: host_id,
name: name,
discovered_health: :unknown,
provider: :unknown,
type: :unknown,
designated_controller: false
}),
[
%ClusterRegistered{
cluster_id: cluster_id,
name: name,
sid: nil,
provider: :unknown,
type: :unknown,
health: :unknown,
details: nil
},
%HostAddedToCluster{
cluster_id: cluster_id,
host_id: host_id
}
],
%Cluster{
cluster_id: cluster_id,
name: name,
sid: nil,
type: :unknown,
provider: :unknown,
hosts: [host_id],
discovered_health: :unknown,
health: :unknown
}
)
end

test "should add a host to the cluster if the host is not a DC and the cluster is already registered" do
cluster_id = Faker.UUID.v4()
host_id = Faker.UUID.v4()
name = Faker.StarWars.character()
Expand Down Expand Up @@ -116,20 +160,47 @@ defmodule Trento.ClusterTest do
)
end

test "should return an error if the cluster was not registered yet and a command from a non-DC is received" do
assert_error(
[],
test "should add a host to the cluster if the host is a DC and the cluster is already registered" do
cluster_id = Faker.UUID.v4()
host_id = Faker.UUID.v4()
name = Faker.StarWars.character()
sid = Faker.StarWars.planet()

assert_events_and_state(
[
build(
:cluster_registered_event,
cluster_id: cluster_id,
provider: :azure,
sid: sid,
name: name,
details: nil
),
build(:host_added_to_cluster_event, cluster_id: cluster_id)
],
RegisterClusterHost.new!(%{
cluster_id: Faker.UUID.v4(),
host_id: Faker.UUID.v4(),
name: Faker.StarWars.character(),
sid: Faker.StarWars.planet(),
discovered_health: :unknown,
cluster_id: cluster_id,
host_id: host_id,
name: name,
sid: sid,
type: :hana_scale_up,
designated_controller: false,
discovered_health: :passing,
resources_number: 8,
hosts_number: 2,
designated_controller: true,
provider: :azure
}),
{:error, :cluster_not_found}
[
%HostAddedToCluster{
cluster_id: cluster_id,
host_id: host_id
}
],
fn cluster ->
assert %Cluster{
hosts: [^host_id | _]
} = cluster
end
)
end
end
Expand Down Expand Up @@ -262,6 +333,7 @@ defmodule Trento.ClusterTest do

test "should use discovered cluster health when no checks are selected" do
cluster_id = Faker.UUID.v4()
host_id = Faker.UUID.v4()
name = Faker.StarWars.character()
sid = Faker.StarWars.planet()

Expand All @@ -274,11 +346,17 @@ defmodule Trento.ClusterTest do
sid: sid,
details: nil,
provider: :azure
),
build(
:host_added_to_cluster_event,
cluster_id: cluster_id,
host_id: host_id
)
],
[
build(
:register_cluster_host,
host_id: host_id,
cluster_id: cluster_id,
name: name,
sid: sid,
Expand Down

0 comments on commit 3c0a318

Please sign in to comment.