diff --git a/assets/js/components/ChecksResults.jsx b/assets/js/components/ChecksResults.jsx index 42742b9ed1..4887c6cef1 100644 --- a/assets/js/components/ChecksResults.jsx +++ b/assets/js/components/ChecksResults.jsx @@ -10,14 +10,16 @@ import LoadingBox from './LoadingBox'; const getChecksResults = (cluster) => { if (cluster) { - return cluster.checks_results.reduce((acc, checkResult) => { - acc[checkResult.host_id] = [ - ...(acc[checkResult.host_id] || []), - checkResult, - ]; - - return acc; - }, {}); + return cluster.checks_results + .filter((check_result) => check_result.result != 'skipped') // Filter "skipped" results by now + .reduce((acc, checkResult) => { + acc[checkResult.host_id] = [ + ...(acc[checkResult.host_id] || []), + checkResult, + ]; + + return acc; + }, {}); } return {}; }; diff --git a/lib/trento/application/event_handlers/checks_event_handler.ex b/lib/trento/application/event_handlers/checks_event_handler.ex index 9286383d77..a9fe6ac4c6 100644 --- a/lib/trento/application/event_handlers/checks_event_handler.ex +++ b/lib/trento/application/event_handlers/checks_event_handler.ex @@ -8,6 +8,7 @@ defmodule Trento.ChecksEventHandler do name: "checks_event_handler" alias Trento.Domain.Events.ChecksExecutionRequested + alias Trento.Hosts alias Trento.Integration.Checks require Logger @@ -16,18 +17,23 @@ defmodule Trento.ChecksEventHandler do %ChecksExecutionRequested{cluster_id: cluster_id, hosts: hosts, checks: checks}, %{correlation_id: execution_id} ) do - case Checks.request_execution(execution_id, cluster_id, hosts, checks) do + hosts_settings = + hosts + |> Enum.map(fn host -> Hosts.get_connection_settings(host) end) + |> Enum.filter(& &1) + + case Checks.request_execution(execution_id, cluster_id, hosts_settings, checks) do :ok -> TrentoWeb.Endpoint.broadcast("monitoring:clusters", "checks_execution_requested", %{ cluster_id: cluster_id }) - {:error, reason} = error -> + {:error, reason} -> Logger.error("Failed to request checks execution for cluster #{cluster_id}: #{reason}", error: reason ) - error + {:error, reason} end end end diff --git a/lib/trento/application/integration/checks/adapter/gen.ex b/lib/trento/application/integration/checks/adapter/gen.ex index 6032d29b6a..3b77b58282 100644 --- a/lib/trento/application/integration/checks/adapter/gen.ex +++ b/lib/trento/application/integration/checks/adapter/gen.ex @@ -7,8 +7,8 @@ defmodule Trento.Integration.Checks.Gen do @callback request_execution( execution_id :: String.t(), - cluster_id :: [String.t()], - hosts :: String.t(), + cluster_id :: String.t(), + hosts_settings :: [map], checks :: [String.t()] ) :: :ok | {:error, any} diff --git a/lib/trento/application/integration/checks/adapter/mock_runner.ex b/lib/trento/application/integration/checks/adapter/mock_runner.ex index 040633c52a..ac147dfba8 100644 --- a/lib/trento/application/integration/checks/adapter/mock_runner.ex +++ b/lib/trento/application/integration/checks/adapter/mock_runner.ex @@ -36,7 +36,7 @@ defmodule Trento.Integration.Checks.MockRunner do @impl true def handle_cast( - {:request_execution, execution_id, cluster_id, hosts, checks}, + {:request_execution, execution_id, cluster_id, hosts_settings, checks}, %__MODULE__{ expected_results: expected_results } @@ -49,7 +49,7 @@ defmodule Trento.Integration.Checks.MockRunner do send_execution_completed_event( execution_id, cluster_id, - hosts, + Enum.map(hosts_settings, fn host -> host.host_id end), checks, expected_results ) @@ -65,10 +65,10 @@ defmodule Trento.Integration.Checks.MockRunner do end @impl true - def request_execution(execution_id, cluster_id, hosts, checks) do + def request_execution(execution_id, cluster_id, hosts_settings, checks) do GenServer.cast( __MODULE__, - {:request_execution, execution_id, cluster_id, hosts, checks} + {:request_execution, execution_id, cluster_id, hosts_settings, checks} ) end diff --git a/lib/trento/application/integration/checks/adapter/runner.ex b/lib/trento/application/integration/checks/adapter/runner.ex index cb0ac5527c..4956398ed9 100644 --- a/lib/trento/application/integration/checks/adapter/runner.ex +++ b/lib/trento/application/integration/checks/adapter/runner.ex @@ -8,8 +8,21 @@ defmodule Trento.Integration.Checks.Runner do alias Trento.Integration.Checks.FlatCatalogDto @impl true - def request_execution(_execution_id, _cluster_id, _hosts, _selected_checks) do - :ok + def request_execution(execution_id, cluster_id, hosts_settings, selected_checks) do + runner_url = runner_url() + + payload = build_payload(execution_id, cluster_id, hosts_settings, selected_checks) + + case HTTPoison.post("#{runner_url}/api/execute", payload) do + {:ok, %HTTPoison.Response{status_code: 202}} -> + :ok + + {:error, %HTTPoison.Error{reason: reason}} -> + {:error, reason} + + _ -> + {:error, :unexpected_response} + end end @impl true @@ -34,6 +47,29 @@ defmodule Trento.Integration.Checks.Runner do end end + defp build_payload(execution_id, cluster_id, host_settings, selected_checks) do + %{ + execution_id: execution_id, + clusters: [ + %{ + cluster_id: cluster_id, + # TODO: Use the correct provider + provider: :azure, + checks: selected_checks, + hosts: + Enum.map(host_settings, fn host -> + %{ + host_id: host.host_id, + address: host.ssh_address, + user: host.user || "root" + } + end) + } + ] + } + |> Jason.encode!() + end + defp runner_url, do: Application.fetch_env!(:trento, __MODULE__)[:runner_url] end diff --git a/lib/trento/application/integration/checks/checks.ex b/lib/trento/application/integration/checks/checks.ex index 328c33f8d7..a05ad6e6f6 100644 --- a/lib/trento/application/integration/checks/checks.ex +++ b/lib/trento/application/integration/checks/checks.ex @@ -14,10 +14,10 @@ defmodule Trento.Integration.Checks do FlatCatalogDto } - @spec request_execution(String.t(), String.t(), [String.t()], [String.t()]) :: + @spec request_execution(String.t(), String.t(), [map], [String.t()]) :: :ok | {:error, any} - def request_execution(execution_id, cluster_id, hosts, selected_checks), - do: adapter().request_execution(execution_id, cluster_id, hosts, selected_checks) + def request_execution(execution_id, cluster_id, host_settings, selected_checks), + do: adapter().request_execution(execution_id, cluster_id, host_settings, selected_checks) @spec get_catalog :: {:ok, FlatCatalogDto.t()} | {:error, any} diff --git a/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex b/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex index 1af7ac31d1..2fa4dc7512 100644 --- a/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex +++ b/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex @@ -15,7 +15,7 @@ defmodule Trento.Integration.Checks.ExecutionCompletedEventDto do embeds_many :results, Result do field :check_id, :string - field :result, Ecto.Enum, values: [:passing, :warning, :critical] + field :result, Ecto.Enum, values: [:passing, :warning, :critical, :skipped] end end end diff --git a/lib/trento/application/read_models/check_result_read_model.ex b/lib/trento/application/read_models/check_result_read_model.ex index e437902f43..e54aaef53a 100644 --- a/lib/trento/application/read_models/check_result_read_model.ex +++ b/lib/trento/application/read_models/check_result_read_model.ex @@ -15,7 +15,7 @@ defmodule Trento.CheckResultReadModel do field :cluster_id, Ecto.UUID, primary_key: true field :host_id, Ecto.UUID, primary_key: true field :check_id, :string, primary_key: true - field :result, Ecto.Enum, values: [:passing, :warning, :critical, :unknown] + field :result, Ecto.Enum, values: [:passing, :warning, :critical, :skipped, :unknown] timestamps() end diff --git a/lib/trento/application/usecases/hosts/host_connection_settings.ex b/lib/trento/application/usecases/hosts/host_connection_settings.ex new file mode 100644 index 0000000000..11d5e537e9 --- /dev/null +++ b/lib/trento/application/usecases/hosts/host_connection_settings.ex @@ -0,0 +1,19 @@ +defmodule Trento.HostConnectionSettings do + @moduledoc false + + use Ecto.Schema + + import Ecto.Changeset + + @type t :: %__MODULE__{} + + @primary_key {:id, :binary_id, autogenerate: false} + schema "host_connection_settings" do + field :user, :string + end + + @spec changeset(t() | Ecto.Changeset.t(), map) :: Ecto.Changeset.t() + def changeset(connection_settings, attrs) do + cast(connection_settings, attrs, [:id, :user]) + end +end diff --git a/lib/trento/application/usecases/hosts/hosts.ex b/lib/trento/application/usecases/hosts/hosts.ex index 1e709dac14..776631169f 100644 --- a/lib/trento/application/usecases/hosts/hosts.ex +++ b/lib/trento/application/usecases/hosts/hosts.ex @@ -6,6 +6,7 @@ defmodule Trento.Hosts do import Ecto.Query alias Trento.{ + HostConnectionSettings, HostReadModel, SlesSubscriptionReadModel } @@ -36,4 +37,16 @@ defmodule Trento.Hosts do subscription_count end end + + @spec get_connection_settings(String.t()) :: map | {:error, any} + def get_connection_settings(host_id) do + query = + from h in HostReadModel, + left_join: s in HostConnectionSettings, + on: h.id == s.id, + select: %{host_id: h.id, ssh_address: h.ssh_address, user: s.user}, + where: h.id == ^host_id + + Repo.one(query) + end end diff --git a/lib/trento/domain/cluster/cluster.ex b/lib/trento/domain/cluster/cluster.ex index 6b3aabfd5f..282b35c1c0 100644 --- a/lib/trento/domain/cluster/cluster.ex +++ b/lib/trento/domain/cluster/cluster.ex @@ -363,6 +363,7 @@ defmodule Trento.Domain.Cluster do hosts_checks_results |> Enum.flat_map(fn {_, results} -> results end) |> Enum.map(fn %{result: result} -> result end) + |> Enum.reject(fn result -> result == :skipped end) |> HealthService.compute_aggregated_health() if new_health != health do diff --git a/lib/trento/domain/cluster/events/checks_execution_completed.ex b/lib/trento/domain/cluster/events/checks_execution_completed.ex index e5c56de668..510e215bc5 100644 --- a/lib/trento/domain/cluster/events/checks_execution_completed.ex +++ b/lib/trento/domain/cluster/events/checks_execution_completed.ex @@ -6,6 +6,6 @@ defmodule Trento.Domain.Events.ChecksExecutionCompleted do use Trento.Event defevent do - field :cluster_id, :string + field :cluster_id, Ecto.UUID end end diff --git a/lib/trento/domain/cluster/events/checks_execution_requested.ex b/lib/trento/domain/cluster/events/checks_execution_requested.ex index 1c434993bd..2b5e9238e9 100644 --- a/lib/trento/domain/cluster/events/checks_execution_requested.ex +++ b/lib/trento/domain/cluster/events/checks_execution_requested.ex @@ -6,8 +6,8 @@ defmodule Trento.Domain.Events.ChecksExecutionRequested do use Trento.Event defevent do - field :cluster_id, :string - field :hosts, {:array, :string} + field :cluster_id, Ecto.UUID + field :hosts, {:array, Ecto.UUID} field :checks, {:array, :string} end end diff --git a/lib/trento/domain/value_objects/check_result.ex b/lib/trento/domain/value_objects/check_result.ex index 5351176df2..9fe90e3871 100644 --- a/lib/trento/domain/value_objects/check_result.ex +++ b/lib/trento/domain/value_objects/check_result.ex @@ -9,6 +9,6 @@ defmodule Trento.Domain.CheckResult do deftype do field :check_id, :string - field :result, Ecto.Enum, values: [:passing, :warning, :critical] + field :result, Ecto.Enum, values: [:passing, :warning, :critical, :skipped] end end diff --git a/priv/repo/migrations/20220404142441_create_host_connection_settings.exs b/priv/repo/migrations/20220404142441_create_host_connection_settings.exs new file mode 100644 index 0000000000..8aeeac2e20 --- /dev/null +++ b/priv/repo/migrations/20220404142441_create_host_connection_settings.exs @@ -0,0 +1,10 @@ +defmodule Trento.Repo.Migrations.CreateHostConnectionSettings do + use Ecto.Migration + + def change do + create table(:host_connection_settings, primary_key: false) do + add :id, :uuid, primary_key: true + add :user, :string + end + end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index 4eb8d52299..9fd19f0c4a 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -37,6 +37,7 @@ defmodule Trento.Factory do ClusterReadModel, DatabaseInstanceReadModel, DatabaseReadModel, + HostConnectionSettings, HostReadModel, HostTelemetryReadModel, SapSystemReadModel, @@ -80,13 +81,20 @@ defmodule Trento.Factory do id: Keyword.get(attrs, :id, Faker.UUID.v4()), hostname: Keyword.get(attrs, :hostname, Faker.StarWars.character()), ip_addresses: [Faker.Internet.ip_v4_address()], - ssh_address: Faker.Internet.ip_v4_address(), + ssh_address: Keyword.get(attrs, :ssh_address, Faker.Internet.ip_v4_address()), agent_version: Faker.StarWars.planet(), cluster_id: Keyword.get(attrs, :cluster_id, Faker.UUID.v4()), heartbeat: :unknown }) end + def host_connection_settings_projection(attrs \\ []) do + Repo.insert!(%HostConnectionSettings{ + id: Keyword.get(attrs, :id, Faker.UUID.v4()), + user: Keyword.get(attrs, :user, Faker.StarWars.character()) + }) + end + def cluster_registered_event(attrs \\ []) do %ClusterRegistered{ cluster_id: Keyword.get(attrs, :cluster_id, Faker.UUID.v4()), diff --git a/test/trento/application/event_handlers/checks_event_handler_test.exs b/test/trento/application/event_handlers/checks_event_handler_test.exs index 64b40a974b..963f13d24b 100644 --- a/test/trento/application/event_handlers/checks_event_handler_test.exs +++ b/test/trento/application/event_handlers/checks_event_handler_test.exs @@ -1,16 +1,38 @@ defmodule Trento.ChecksEventHandlerTest do use ExUnit.Case + use Trento.DataCase import Mox + import Trento.Factory + alias Trento.ChecksEventHandler alias Trento.Domain.Events.ChecksExecutionRequested test "should request a checks execution when the ChecksExecutionRequested event is received" do + host_id_1 = Faker.UUID.v4() + host_projection(id: host_id_1, ssh_address: "192.168.1.1") + + host_id_2 = Faker.UUID.v4() + host_projection(id: host_id_2, ssh_address: "192.168.1.2") + + expected_hosts = [ + %{ + host_id: host_id_1, + ssh_address: "192.168.1.1", + user: nil + }, + %{ + host_id: host_id_2, + ssh_address: "192.168.1.2", + user: nil + } + ] + event = ChecksExecutionRequested.new!(%{ cluster_id: Faker.UUID.v4(), - hosts: ["hostname1", "hostname2"], + hosts: [host_id_1, host_id_2], checks: ["check1", "check2"] }) @@ -22,7 +44,7 @@ defmodule Trento.ChecksEventHandlerTest do checks -> assert correlation_id == execution_id assert event.cluster_id == cluster_id - assert event.hosts == hosts + assert expected_hosts == hosts assert event.checks == checks :ok end) diff --git a/test/trento/application/usecases/hosts_test.exs b/test/trento/application/usecases/hosts_test.exs index b0b031511f..2235a8ff7b 100644 --- a/test/trento/application/usecases/hosts_test.exs +++ b/test/trento/application/usecases/hosts_test.exs @@ -28,4 +28,16 @@ defmodule Trento.HostsTest do assert 6 = Hosts.get_all_sles_subscriptions() end end + + describe "Connection settings" do + test "Returns connection settings map" do + host_id = Faker.UUID.v4() + host_projection(id: host_id, ssh_address: "192.168.1.1") + + host_connection_settings_projection(id: host_id, user: "root") + + assert %{host_id: host_id, ssh_address: "192.168.1.1", user: "root"} == + Hosts.get_connection_settings(host_id) + end + end end