diff --git a/config/config.exs b/config/config.exs index 988dcf3037..938290ee37 100644 --- a/config/config.exs +++ b/config/config.exs @@ -107,6 +107,13 @@ config :trento, Trento.Scheduler, task: {Trento.Clusters, :request_clusters_checks_execution, []}, run_strategy: {Quantum.RunStrategy.Random, :cluster}, overlap: false + ], + hosts_checks_execution: [ + # Runs every five minutes + schedule: "*/5 * * * *", + task: {Trento.Hosts, :request_hosts_checks_execution, []}, + run_strategy: {Quantum.RunStrategy.Random, :cluster}, + overlap: false ] ], debug_logging: false diff --git a/config/demo.exs b/config/demo.exs index 4441730a03..7fb38efc40 100644 --- a/config/demo.exs +++ b/config/demo.exs @@ -15,6 +15,9 @@ config :trento, Trento.Scheduler, clusters_checks_execution: [ schedule: {:extended, "@hourly"} ], + hosts_checks_execution: [ + schedule: {:extended, "@hourly"} + ], heartbeat_fake: [ schedule: {:extended, "*/5"}, task: {Trento.Heartbeats.Faker, :send_heartbeats, []}, diff --git a/config/dev.exs b/config/dev.exs index 38bed0df34..9a125e3d67 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -92,6 +92,9 @@ unless IEx.started?() do ], clusters_checks_execution: [ schedule: {:extended, "@hourly"} + ], + hosts_checks_execution: [ + schedule: {:extended, "@hourly"} ] ] end diff --git a/config/runtime.exs b/config/runtime.exs index ff2acf17ef..726ff9d4ad 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -134,8 +134,11 @@ if config_env() in [:prod, :demo] do config :trento, Trento.Scheduler, jobs: [ + # Runs every five minutes by default clusters_checks_execution: [ - # Runs every five minutes by default + schedule: "*/#{System.get_env("CHECKS_INTERVAL", "5")} * * * *" + ], + hosts_checks_execution: [ schedule: "*/#{System.get_env("CHECKS_INTERVAL", "5")} * * * *" ] ] diff --git a/lib/trento/application/usecases/hosts/hosts.ex b/lib/trento/application/usecases/hosts/hosts.ex index 7629bda1ce..c7bd852f20 100644 --- a/lib/trento/application/usecases/hosts/hosts.ex +++ b/lib/trento/application/usecases/hosts/hosts.ex @@ -60,6 +60,26 @@ defmodule Trento.Hosts do end end + def request_hosts_checks_execution do + query = + from(h in HostReadModel, + select: h.id, + where: is_nil(h.deregistered_at) + ) + + query + |> Repo.all() + |> Enum.each(fn host_id -> + case request_checks_execution(host_id) do + :ok -> + :ok + + {:error, reason} -> + Logger.error("Failed to request checks execution, host: #{host_id}, reason: #{reason}") + end + end) + end + @spec select_checks(String.t(), [String.t()]) :: :ok | {:error, any} def select_checks(host_id, checks) do Logger.debug("Selecting checks, host: #{host_id}") diff --git a/test/trento/application/usecases/clusters_test.exs b/test/trento/application/usecases/clusters_test.exs index fd57ffc582..02805b1b3b 100644 --- a/test/trento/application/usecases/clusters_test.exs +++ b/test/trento/application/usecases/clusters_test.exs @@ -7,10 +7,15 @@ defmodule Trento.ClustersTest do import Trento.Factory - alias Trento.Clusters + alias Trento.{ClusterEnrichmentData, ClusterReadModel, Clusters} - alias Trento.ClusterEnrichmentData - alias Trento.ClusterReadModel + alias Trento.Checks.V1.{ + ExecutionRequested, + Target + } + + require Trento.Domain.Enums.ClusterType + require Logger setup [:set_mox_from_context, :verify_on_exit!] @@ -64,6 +69,62 @@ defmodule Trento.ClustersTest do assert {:error, :amqp_error} = Clusters.request_checks_execution(cluster_id) end + + test "should request cluster checks execution when checks are selected" do + checks = [Faker.UUID.v4(), Faker.UUID.v4()] + %{id: cluster_id} = insert(:cluster, id: Faker.UUID.v4(), selected_checks: checks) + %{id: host_id1} = insert(:host, id: Faker.UUID.v4(), cluster_id: cluster_id) + %{id: host_id2} = insert(:host, id: Faker.UUID.v4(), cluster_id: cluster_id) + + %{id: cluster_id2} = + insert(:cluster, + id: Faker.UUID.v4(), + selected_checks: checks, + deregistered_at: DateTime.utc_now() + ) + + %{id: host_id3} = insert(:host, id: Faker.UUID.v4(), cluster_id: cluster_id2) + %{id: host_id4} = insert(:host, id: Faker.UUID.v4(), cluster_id: cluster_id2) + + expect(Trento.Infrastructure.Messaging.Adapter.Mock, :publish, fn "executions", + %ExecutionRequested{ + group_id: ^cluster_id, + targets: [ + %Target{ + agent_id: ^host_id1, + checks: ^checks + }, + %Target{ + agent_id: ^host_id2, + checks: ^checks + } + ] + } -> + :ok + end) + + expect(Trento.Infrastructure.Messaging.Adapter.Mock, :publish, 0, fn "executions", + %ExecutionRequested{ + group_id: + ^cluster_id2, + targets: [ + %Target{ + agent_id: + ^host_id3, + checks: ^checks + }, + %Target{ + agent_id: + ^host_id4, + checks: ^checks + } + ] + } -> + :ok + end) + + assert :ok = Clusters.request_clusters_checks_execution() + end end describe "get clusters" do diff --git a/test/trento/application/usecases/hosts_test.exs b/test/trento/application/usecases/hosts_test.exs index 76240e7819..887b7c1791 100644 --- a/test/trento/application/usecases/hosts_test.exs +++ b/test/trento/application/usecases/hosts_test.exs @@ -2,17 +2,19 @@ defmodule Trento.HostsTest do use ExUnit.Case use Trento.DataCase - import Mox - + import ExUnit.CaptureLog import Trento.Factory import Mox - alias Trento.Hosts - alias Trento.Repo - alias Trento.Domain.Commands.SelectHostChecks + alias Trento.{Hosts, Repo, SlesSubscriptionReadModel} - alias Trento.SlesSubscriptionReadModel + alias Trento.Checks.V1.{ + ExecutionRequested, + Target + } + + require Logger @moduletag :integration @@ -171,5 +173,56 @@ defmodule Trento.HostsTest do assert {:error, :amqp_error} = Hosts.request_checks_execution(host_id) end + + test "should request host checks execution for hosts when checks are selected" do + checks = [Faker.UUID.v4(), Faker.UUID.v4()] + %{id: host_id1} = insert(:host, id: Faker.UUID.v4(), selected_checks: checks) + + %{id: host_id2} = + insert(:host, + selected_checks: checks, + deregistered_at: DateTime.utc_now() + ) + + expect(Trento.Infrastructure.Messaging.Adapter.Mock, :publish, 1, fn "executions", + %ExecutionRequested{ + group_id: ^host_id1, + targets: [ + %Target{ + agent_id: + ^host_id1, + checks: ^checks + } + ] + } -> + :ok + end) + + expect(Trento.Infrastructure.Messaging.Adapter.Mock, :publish, 0, fn "executions", + %ExecutionRequested{ + group_id: ^host_id2, + targets: [ + %Target{ + agent_id: + ^host_id2, + checks: ^checks + } + ] + } -> + :ok + end) + + assert :ok = Hosts.request_hosts_checks_execution() + end + + test "should log an error message when host checks execution is requested but no checks selected" do + %{id: host_id} = insert(:host, selected_checks: []) + + expected_logger_message = + "Failed to request checks execution, host: #{host_id}, reason: no_checks_selected" + + assert capture_log(fn -> Hosts.request_hosts_checks_execution() end) =~ + expected_logger_message + end end end