Skip to content

Commit

Permalink
Log host checks execution request (#2957)
Browse files Browse the repository at this point in the history
* Align host and cluster behavior on requesting checks execution for an empty selection

* Add host checks execution request to the Activity Catalog

* Parse metadata for checks execution requests

* Enhance ActivityLogger testing with checks execution requests scenarios

* Map newly added host checks execution request activity in the UI

* Refactor checks execution request metadata extraction
  • Loading branch information
nelsonkopliku authored Sep 17, 2024
1 parent efaa0e4 commit d26b38f
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 2 deletions.
6 changes: 6 additions & 0 deletions assets/js/lib/model/activityLog.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const USER_DELETION = 'user_deletion';
export const PROFILE_UPDATE = 'profile_update';
export const CLUSTER_CHECKS_EXECUTION_REQUEST =
'cluster_checks_execution_request';
export const HOST_CHECKS_EXECUTION_REQUEST = 'host_checks_execution_request';
export const ACTIVITY_LOG_SETTINGS_UPDATE = 'activity_log_settings_update';

// Host events
Expand Down Expand Up @@ -188,6 +189,11 @@ export const ACTIVITY_TYPES_CONFIG = {
message: (_entry) => `Checks execution requested for cluster`,
resource: clusterResourceType,
},
[HOST_CHECKS_EXECUTION_REQUEST]: {
label: 'Checks Execution Requested',
message: (_entry) => `Checks execution requested for host`,
resource: hostResourceType,
},
[ACTIVITY_LOG_SETTINGS_UPDATE]: {
label: 'Activity Log Settings Updated',
message: (_entry) => `Activity log settings were updated`,
Expand Down
2 changes: 2 additions & 0 deletions lib/trento/activity_logging/activity_catalog.ex
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ defmodule Trento.ActivityLog.ActivityCatalog do
{TrentoWeb.V1.ProfileController, :update} => {:profile_update, 200},
{TrentoWeb.V1.ClusterController, :request_checks_execution} =>
{:cluster_checks_execution_request, 202},
{TrentoWeb.V1.HostController, :request_checks_execution} =>
{:host_checks_execution_request, 202},
{TrentoWeb.V1.SettingsController, :update_activity_log_settings} =>
{:activity_log_settings_update, 200}
}
Expand Down
16 changes: 16 additions & 0 deletions lib/trento/activity_logging/parser/phoenix_conn_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,22 @@ defmodule Trento.ActivityLog.Logger.Parser.PhoenixConnParser do
|> redact(:password_confirmation)
end

def get_activity_metadata(
:cluster_checks_execution_request,
%Plug.Conn{
params: params
}
),
do: %{cluster_id: Map.get(params, :cluster_id)}

def get_activity_metadata(
:host_checks_execution_request,
%Plug.Conn{
params: params
}
),
do: %{host_id: Map.get(params, :id)}

def get_activity_metadata(_, _), do: %{}

defp redact(request_body, key) do
Expand Down
3 changes: 2 additions & 1 deletion lib/trento/clusters.ex
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ defmodule Trento.Clusters do
end
end

defp maybe_request_checks_execution(%ClusterReadModel{selected_checks: []}), do: :ok
defp maybe_request_checks_execution(%ClusterReadModel{selected_checks: []}),
do: {:error, :no_checks_selected}

defp maybe_request_checks_execution(%ClusterReadModel{
id: cluster_id,
Expand Down
19 changes: 19 additions & 0 deletions test/support/messaging_case.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
defmodule Trento.MessagingCase do
@moduledoc """
This test case makes sure that the messaging system is properly stubbed for tests where a defined behavior is sufficient.
"""

use ExUnit.CaseTemplate

setup _ do
Mox.stub(
Trento.Infrastructure.Messaging.Adapter.Mock,
:publish,
fn _, _ ->
:ok
end
)

:ok
end
end
1 change: 1 addition & 0 deletions test/trento/activity_logging/activity_catalog_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ defmodule Trento.ActivityLog.ActivityCatalogTest do
:user_deletion,
:profile_update,
:cluster_checks_execution_request,
:host_checks_execution_request,
:activity_log_settings_update
]

Expand Down
94 changes: 94 additions & 0 deletions test/trento/activity_logging/activity_logger_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule Trento.ActivityLog.ActivityLoggerTest do
@moduledoc false

use TrentoWeb.ConnCase, async: true
use Trento.MessagingCase
use Plug.Test

import Trento.Factory
Expand Down Expand Up @@ -254,6 +255,99 @@ defmodule Trento.ActivityLog.ActivityLoggerTest do
end
end

describe "checks execution request activity detection" do
defp request_checks_execution(conn, component_id, component_type) do
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/#{component_type}/#{component_id}/checks/request_execution")
end

test "should not log a checks execution request failing because of a non existent resource",
%{conn: conn, user: %{id: user_id}} do
for component_type <- ["clusters", "hosts"] do
conn
|> with_token(user_id)
|> request_checks_execution(Faker.UUID.v4(), component_type)
|> json_response(404)

wait_for_tasks_completion()

assert [] = Trento.Repo.all(ActivityLog)
end
end

test "should not log a checks execution request failing because of empty checks selection", %{
conn: conn,
user: %{id: user_id}
} do
for {component_type, factory_reference} <- [{"clusters", :cluster}, {"hosts", :host}] do
%{id: component_id} = insert(factory_reference, selected_checks: [])

conn
|> with_token(user_id)
|> request_checks_execution(component_id, component_type)
|> json_response(422)

wait_for_tasks_completion()

assert [] = Trento.Repo.all(ActivityLog)
end
end

successful_checks_execution_request_scenarios = [
%{
component_type: "clusters",
factory_reference: :cluster,
expected_activity_type: "cluster_checks_execution_request",
expected_metadata_entry: "cluster_id"
},
%{
component_type: "hosts",
factory_reference: :host,
expected_activity_type: "host_checks_execution_request",
expected_metadata_entry: "host_id"
}
]

for %{component_type: component_type} = scenario <-
successful_checks_execution_request_scenarios do
@scenario scenario

test "should log a successful checks execution request for #{component_type}", %{
conn: conn,
user: %{id: user_id, username: username}
} do
%{
component_type: component_type,
factory_reference: factory_reference,
expected_activity_type: expected_activity_type,
expected_metadata_entry: expected_metadata_entry
} = @scenario

%{id: component_id} = insert(factory_reference)

conn
|> with_token(user_id)
|> request_checks_execution(component_id, component_type)
|> json_response(202)

wait_for_tasks_completion()

expected_metadata = %{
expected_metadata_entry => component_id
}

assert [
%ActivityLog{
type: ^expected_activity_type,
actor: ^username,
metadata: ^expected_metadata
}
] = Trento.Repo.all(ActivityLog)
end
end
end

test "domain event activity logging" do
heartbeat_succeeded_event = build(:heartbeat_succeded)
heartbeat_failed_event = build(:heartbeat_failed)
Expand Down
40 changes: 40 additions & 0 deletions test/trento/activity_logging/phoenix_conn_parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,46 @@ defmodule Trento.ActivityLog.PhoenixConnParserTest do
})
end
end

test "should extract component id when requesting checks execution", %{conn: conn} do
host_id = Faker.UUID.v4()
cluster_id = Faker.UUID.v4()

scenarios = [
%{
action: :cluster_checks_execution_request,
params: %{:cluster_id => cluster_id},
expected_metadata: %{:cluster_id => cluster_id}
},
%{
action: :host_checks_execution_request,
params: %{:id => host_id},
expected_metadata: %{:host_id => host_id}
},
%{
action: :host_checks_execution_request,
params: %{:foo => "bar"},
expected_metadata: %{:host_id => nil}
},
%{
action: :cluster_checks_execution_request,
params: %{:foo => "bar"},
expected_metadata: %{:cluster_id => nil}
}
]

for %{
action: action,
params: params,
expected_metadata: expected_metadata
} <- scenarios do
assert expected_metadata ==
PhoenixConnParser.get_activity_metadata(action, %Plug.Conn{
conn
| params: params
})
end
end
end

defp assert_for_relevant_activity(assertion_function) do
Expand Down
2 changes: 1 addition & 1 deletion test/trento/clusters_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ defmodule Trento.ClustersTest do
:ok
end)

assert :ok = Clusters.request_checks_execution(cluster_id)
assert {:error, :no_checks_selected} = Clusters.request_checks_execution(cluster_id)
end

test "should return an error if the checks execution start fails" do
Expand Down
18 changes: 18 additions & 0 deletions test/trento_web/controllers/v1/cluster_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ defmodule TrentoWeb.V1.ClusterControllerTest do
} == resp
end

test "should return 422 when the selection is empty", %{conn: conn} do
%{id: cluster_id} = insert(:cluster, selected_checks: [])

resp =
conn
|> post("/api/v1/clusters/#{cluster_id}/checks/request_execution")
|> json_response(:unprocessable_entity)

assert %{
"errors" => [
%{
"title" => "Unprocessable Entity",
"detail" => "No checks were selected for the target."
}
]
} == resp
end

test "should return 500 if messaging returns an error", %{conn: conn} do
expect(
Trento.Infrastructure.Messaging.Adapter.Mock,
Expand Down

0 comments on commit d26b38f

Please sign in to comment.