From 5231cad45e835503ba2db76d4e949530ce7fa59f Mon Sep 17 00:00:00 2001 From: EMaksy Date: Wed, 21 Jun 2023 17:31:40 +0200 Subject: [PATCH 1/4] Add host selection projector --- .../application/projectors/host_projector.ex | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/trento/application/projectors/host_projector.ex b/lib/trento/application/projectors/host_projector.ex index ac5c64f7f0..1a070cc517 100644 --- a/lib/trento/application/projectors/host_projector.ex +++ b/lib/trento/application/projectors/host_projector.ex @@ -16,6 +16,7 @@ defmodule Trento.HostProjector do HeartbeatFailed, HeartbeatSucceded, HostAddedToCluster, + HostChecksSelected, HostDetailsUpdated, HostRegistered, ProviderUpdated @@ -84,6 +85,26 @@ defmodule Trento.HostProjector do end ) + project( + %HostChecksSelected{ + host_id: id, + checks: checks + }, + fn multi -> + changeset = + HostReadModel + |> Repo.get(id) + # TODO: couldn't make it work with Ecto.Multi + # With following line when we receive an empty list of selected checks, the readmodel does not get updated + # %ClusterReadModel{id: id} + |> HostReadModel.changeset(%{ + selected_checks: checks + }) + + Ecto.Multi.update(multi, :host, changeset) + end + ) + project( %HeartbeatSucceded{host_id: id}, fn multi -> @@ -228,5 +249,19 @@ defmodule Trento.HostProjector do }) end + def after_update( + %HostChecksSelected{checks: checks}, + _, + %{host: %HostReadModel{id: id}} + ) do + message = + HostView.render( + "host_checks_updated.json", + %{host: %HostReadModel{id: id, selected_checks: checks}} + ) + + TrentoWeb.Endpoint.broadcast("monitoring:hosts", "host_checks_updated", message) + end + def after_update(_, _, _), do: :ok end From 0e4b525d8cb9fdaf79444a8f7739df870515f5db Mon Sep 17 00:00:00 2001 From: EMaksy Date: Wed, 21 Jun 2023 17:32:27 +0200 Subject: [PATCH 2/4] Update host read model and add migration --- lib/trento/application/read_models/host_read_model.ex | 2 +- .../20230616114036_add_selected_checks_to_hosts.exs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 priv/repo/migrations/20230616114036_add_selected_checks_to_hosts.exs diff --git a/lib/trento/application/read_models/host_read_model.ex b/lib/trento/application/read_models/host_read_model.ex index 0333807e78..cb79ce7363 100644 --- a/lib/trento/application/read_models/host_read_model.ex +++ b/lib/trento/application/read_models/host_read_model.ex @@ -21,7 +21,7 @@ defmodule Trento.HostReadModel do field :agent_version, :string field :cluster_id, Ecto.UUID field :heartbeat, Ecto.Enum, values: [:critical, :passing, :unknown] - + field :selected_checks, {:array, :string}, default: [] field :provider, Ecto.Enum, values: Provider.values() field :provider_data, :map diff --git a/priv/repo/migrations/20230616114036_add_selected_checks_to_hosts.exs b/priv/repo/migrations/20230616114036_add_selected_checks_to_hosts.exs new file mode 100644 index 0000000000..1af8f0888c --- /dev/null +++ b/priv/repo/migrations/20230616114036_add_selected_checks_to_hosts.exs @@ -0,0 +1,9 @@ +defmodule Trento.Repo.Migrations.AddSelectedChecksToHosts do + use Ecto.Migration + + def change do + alter table(:hosts) do + add :selected_checks, {:array, :string}, default: [] + end + end +end From 610d75667622aa96339be10ced7381f30a30e654 Mon Sep 17 00:00:00 2001 From: EMaksy Date: Wed, 21 Jun 2023 17:33:22 +0200 Subject: [PATCH 3/4] Add host selected checks view --- lib/trento_web/views/v1/host_view.ex | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/trento_web/views/v1/host_view.ex b/lib/trento_web/views/v1/host_view.ex index 7bdab56a1d..49c638b746 100644 --- a/lib/trento_web/views/v1/host_view.ex +++ b/lib/trento_web/views/v1/host_view.ex @@ -20,6 +20,19 @@ defmodule TrentoWeb.V1.HostView do |> Map.delete(:provider) end + def render("host_checks_updated.json", %{host: host}) do + render("host.json", %{host: host}) + |> Map.delete(:sles_subscriptions) + |> Map.delete(:tags) + |> Map.delete(:cluster_id) + |> Map.delete(:heartbeat) + |> Map.delete(:provider) + |> Map.delete(:agent_version) + |> Map.delete(:hostname) + |> Map.delete(:ip_addresses) + |> Map.delete(:provider_data) + end + def render("host_registered.json", %{host: host}) do render("host.json", %{host: host}) |> Map.delete(:sles_subscriptions) From 29bc27554f9ab22e2bf5289543bba3cfbd453309 Mon Sep 17 00:00:00 2001 From: EMaksy Date: Wed, 21 Jun 2023 17:33:43 +0200 Subject: [PATCH 4/4] Use host_details_updated view and event --- .../projectors/cluster_projector.ex | 3 --- .../application/projectors/host_projector.ex | 15 ++++++------ lib/trento_web/views/v1/host_view.ex | 13 ----------- .../projectors/host_projector_test.exs | 23 +++++++++++++++++++ 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/lib/trento/application/projectors/cluster_projector.ex b/lib/trento/application/projectors/cluster_projector.ex index 1ce45c1f88..f0659eba8f 100644 --- a/lib/trento/application/projectors/cluster_projector.ex +++ b/lib/trento/application/projectors/cluster_projector.ex @@ -89,9 +89,6 @@ defmodule Trento.ClusterProjector do changeset = ClusterReadModel |> Repo.get(id) - # TODO: couldn't make it work with Ecto.Multi - # With following line when we receive an empty list of selected checks, the readmodel does not get updated - # %ClusterReadModel{id: id} |> ClusterReadModel.changeset(%{ selected_checks: checks }) diff --git a/lib/trento/application/projectors/host_projector.ex b/lib/trento/application/projectors/host_projector.ex index 1a070cc517..76a3e10849 100644 --- a/lib/trento/application/projectors/host_projector.ex +++ b/lib/trento/application/projectors/host_projector.ex @@ -94,9 +94,6 @@ defmodule Trento.HostProjector do changeset = HostReadModel |> Repo.get(id) - # TODO: couldn't make it work with Ecto.Multi - # With following line when we receive an empty list of selected checks, the readmodel does not get updated - # %ClusterReadModel{id: id} |> HostReadModel.changeset(%{ selected_checks: checks }) @@ -250,17 +247,19 @@ defmodule Trento.HostProjector do end def after_update( - %HostChecksSelected{checks: checks}, + %HostChecksSelected{host_id: host_id, checks: checks}, _, - %{host: %HostReadModel{id: id}} + _ ) do + host = %HostReadModel{id: host_id, selected_checks: checks} + message = HostView.render( - "host_checks_updated.json", - %{host: %HostReadModel{id: id, selected_checks: checks}} + "host_details_updated.json", + %{host: host} ) - TrentoWeb.Endpoint.broadcast("monitoring:hosts", "host_checks_updated", message) + TrentoWeb.Endpoint.broadcast("monitoring:hosts", "host_details_updated", message) end def after_update(_, _, _), do: :ok diff --git a/lib/trento_web/views/v1/host_view.ex b/lib/trento_web/views/v1/host_view.ex index 49c638b746..7bdab56a1d 100644 --- a/lib/trento_web/views/v1/host_view.ex +++ b/lib/trento_web/views/v1/host_view.ex @@ -20,19 +20,6 @@ defmodule TrentoWeb.V1.HostView do |> Map.delete(:provider) end - def render("host_checks_updated.json", %{host: host}) do - render("host.json", %{host: host}) - |> Map.delete(:sles_subscriptions) - |> Map.delete(:tags) - |> Map.delete(:cluster_id) - |> Map.delete(:heartbeat) - |> Map.delete(:provider) - |> Map.delete(:agent_version) - |> Map.delete(:hostname) - |> Map.delete(:ip_addresses) - |> Map.delete(:provider_data) - end - def render("host_registered.json", %{host: host}) do render("host.json", %{host: host}) |> Map.delete(:sles_subscriptions) diff --git a/test/trento/application/projectors/host_projector_test.exs b/test/trento/application/projectors/host_projector_test.exs index c3e363cb94..3e9f92bec1 100644 --- a/test/trento/application/projectors/host_projector_test.exs +++ b/test/trento/application/projectors/host_projector_test.exs @@ -24,6 +24,7 @@ defmodule Trento.HostProjectorTest do HeartbeatFailed, HeartbeatSucceded, HostAddedToCluster, + HostChecksSelected, HostDetailsUpdated, ProviderUpdated } @@ -166,6 +167,28 @@ defmodule Trento.HostProjectorTest do 1000 end + test "should update the selected_checks field when event is received" do + %{id: host_id} = insert(:host) + + cases = [ + %{checks: [Faker.StarWars.character(), Faker.StarWars.character()]}, + %{checks: []} + ] + + Enum.each(cases, fn %{checks: checks} -> + event = %HostChecksSelected{host_id: host_id, checks: checks} + + ProjectorTestHelper.project(HostProjector, event, "host_projector") + host_projection = Repo.get!(HostReadModel, event.host_id) + + assert event.checks == host_projection.selected_checks + + assert_broadcast "host_details_updated", + %{selected_checks: ^checks, id: ^host_id}, + 1000 + end) + end + test "should update the heartbeat field to passing status when HeartbeatSucceded is received", %{host_id: host_id} do event = %HeartbeatSucceded{