Skip to content

Commit

Permalink
Refactor demo server (#271)
Browse files Browse the repository at this point in the history
* Add a demo env configuration to set expected gathered facts from targets

Co-authored-by: Eugen Maksymenko <[email protected]>

* Add a FakeGatheredFacts module that returns gathered facts for execution

Co-authored-by: Eugen Maksymenko <[email protected]>

* Refactor FakeServer to use the FakeGatheredFacts

Co-authored-by: Eugen Maksymenko <[email protected]>

* Remove randomic FakeEvaluation

Co-authored-by: Eugen Maksymenko <[email protected]>

* Fix CAEFF1 fact values

* Restructure demo config to checkId -> factName -> targetId -> factValue
Co-authored-by: Eugen Maksymenko <[email protected]>

* Move demo config to a seperate yaml config

Co-authored-by: Nelson Kopliku <[email protected]>

* Add additional test when yaml config can't be read

* Remove unused test_helper

* Remove comment

* Add demo documentation

* Improve documentation after comments

---------

Co-authored-by: Nelson Kopliku <[email protected]>
  • Loading branch information
EMaksy and nelsonkopliku authored Jul 27, 2023
1 parent 5f8be53 commit 376870d
Show file tree
Hide file tree
Showing 13 changed files with 923 additions and 339 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,17 @@ To implement new checks and test them:
- locate the newly created Check in the Catalog directory `./priv/catalog/`
- test the execution as [previously described](#testing-executions)

# Installing a development environment
# Running a local Wanda instance

To set up a local development environment for hacking on Wanda, you need to follow the instructions provided in [hack on wanda](./guides/development/hack_on_wanda.md).
## Running a Development Environment

This guide walks you through the process of installing and configuring the necessary dependencies, as well as setting up a local development environment.
To set up a local development environment for Wanda, follow the instructions provided in [how to hack on wanda](./guides/development/hack_on_wanda.md).

This guide walks through the process of installing and configuring the necessary dependencies, as well as setting up a local development environment.

## Running a Demo Environment

The demo mode of Wanda allows to showcase checks evaluation without the full setup with actual agents on the host. To run a demo instance, follow the instructions provided in [how to run wanda demo guide](./guides/development/demo.md).

# Support

Expand Down
2 changes: 2 additions & 0 deletions config/demo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ config :wanda, WandaWeb.Endpoint,
server: true

config :logger, level: :debug

config :wanda, Wanda.Executions.FakeGatheredFacts, demo_facts_config: "priv/demo/fake_facts.yaml"
3 changes: 3 additions & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@ config :joken,

config :wanda,
jwt_authentication_enabled: false

config :wanda, Wanda.Executions.FakeGatheredFacts,
demo_facts_config: "test/fixtures/demo/fake_facts_test.yaml"
96 changes: 0 additions & 96 deletions demo/fake_evaluation.ex

This file was deleted.

72 changes: 72 additions & 0 deletions demo/fake_gathered_facts.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
defmodule Wanda.Executions.FakeGatheredFacts do
@moduledoc """
Module responsible to generate the fake gathered facts from targets
"""

alias Wanda.Catalog.{Check, Fact}
alias Wanda.Executions.Fact, as: ExecutionFact
alias Wanda.Executions.Target

@fallback_fact_value "some fact value"

def get_demo_gathered_facts(checks, targets) do
Enum.reduce(checks, %{}, fn %Check{id: check_id} = check, gathered_facts_map ->
Map.put(gathered_facts_map, check_id, get_check_facts(check, targets))
end)
end

defp get_check_facts(%Check{id: check_id, facts: facts}, targets) do
Enum.reduce(targets, %{}, fn %Target{agent_id: agent_id}, agent_gathered_facts ->
Map.put(agent_gathered_facts, agent_id, get_agent_facts(facts, agent_id, check_id))
end)
end

defp get_agent_facts(facts, agent_id, check_id) do
Enum.map(facts, fn %Fact{name: name} ->
%ExecutionFact{
check_id: check_id,
name: name,
value: get_fake_fact_value(check_id, agent_id, name)
}
end)
end

defp get_fake_fact_value(check_id, agent_id, fact_name) do
with {:ok, target_refs, fake_facts} <- read_from_yaml_config(),
{:ok, target_ref} <- get_target_reference(target_refs, agent_id),
{:ok, fact_value} <- get_fake_value_from_map(fake_facts, check_id, fact_name, target_ref) do
fact_value
else
{:error, _reason} ->
@fallback_fact_value
end
end

defp read_from_yaml_config do
case YamlElixir.read_from_file(get_fake_gathered_facts_config()) do
{:ok, %{"targets" => target_refs, "facts" => fake_facts}} -> {:ok, target_refs, fake_facts}
error -> error
end
end

defp get_fake_value_from_map(fake_facts, check_id, fact_name, target_ref) do
case fake_facts do
%{^check_id => %{^fact_name => %{^target_ref => fact_value}}} ->
{:ok, fact_value}

_ ->
{:error, :value_not_found}
end
end

defp get_target_reference(target_refs, agent_id) do
case Enum.find(target_refs, fn {_, target_id} -> target_id == agent_id end) do
nil -> {:error, :target_ref_not_found}
found_target -> {:ok, elem(found_target, 0)}
end
end

defp get_fake_gathered_facts_config do
Application.fetch_env!(:wanda, __MODULE__)[:demo_facts_config]
end
end
31 changes: 19 additions & 12 deletions demo/fake_server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ defmodule Wanda.Executions.FakeServer do
"""
@behaviour Wanda.Executions.ServerBehaviour

alias Wanda.Executions.FakeEvaluation
alias Wanda.EvaluationEngine
alias Wanda.Executions.{Evaluation, FakeGatheredFacts}

alias Wanda.{
Catalog,
Expand All @@ -16,34 +17,40 @@ defmodule Wanda.Executions.FakeServer do
@default_config [sleep: 2_000]
@impl true
def start_execution(execution_id, group_id, targets, env, config \\ @default_config) do
default_target_type = "cluster"
env = Map.put(env, "target_type", default_target_type)

checks =
targets
|> Executions.Target.get_checks_from_targets()
|> Catalog.get_checks(env)

checks_ids = Enum.map(checks, & &1.id)

target_type = Map.get(env, "target_type", "cluster")

targets =
Enum.map(targets, fn %{checks: target_checks} = target ->
%Executions.Target{target | checks: target_checks -- target_checks -- checks_ids}
end)
gathered_facts = FakeGatheredFacts.get_demo_gathered_facts(checks, targets)

Executions.create_execution!(execution_id, group_id, targets)
execution_started = Messaging.Mapper.to_execution_started(execution_id, group_id, targets)
:ok = Messaging.publish("results", execution_started)

Process.sleep(Keyword.get(config, :sleep, 2_000))

build_result = FakeEvaluation.complete_fake_execution(execution_id, group_id, targets, checks)
evaluation_result =
Evaluation.execute(
execution_id,
group_id,
checks,
gathered_facts,
env,
EvaluationEngine.new()
)

Executions.complete_execution!(
execution_id,
build_result
evaluation_result
)

execution_completed = Messaging.Mapper.to_execution_completed(build_result, target_type)
execution_completed =
Messaging.Mapper.to_execution_completed(evaluation_result, default_target_type)

:ok = Messaging.publish("results", execution_completed)
end

Expand Down
122 changes: 122 additions & 0 deletions guides/development/demo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Wanda Demo

## Introduction

Wanda's demo mode provides a simulated environment where targets' gathered facts are faked via a configuration yaml file. This empowers showcasing Trento's capabilities, and eases the development of the platform. The user is able to run check executions from the web, and wanda's fake server returns faked gathered facts.

## How to setup Wanda in demo mode?

First set up the [local environment](./hack_on_wanda.md) and run the following command to start Wanda in demo mode, instead of the usual `iex -S mix phx.server`

```bash
$ DATABASE_URL=ecto://postgres:postgres@localhost:5434/wanda_dev \
AMQP_URL=amqp://wanda:wanda@localhost:5674 \
SECRET_KEY_BASE=Tbp26GilFTZOXafb7FNVqt4dFQdeb7FAJ++am7ItYx2sMzYaPSB9SwUczdJu6AhQ \
CORS_ORIGIN=http://localhost:4000 \
ACCESS_TOKEN_ENC_SECRET=s2ZdE+3+ke1USHEJ5O45KT364KiXPYaB9cJPdH3p60t8yT0nkLexLBNw8TFSzC7k \
PORT=4001 \
MIX_ENV=demo \
iex -S mix phx.server
```

### Explanation of environment variables:

- DATABASE_URL: The URL to connect to the Postgres database running in the Docker container.
- AMQP_URL: The URL for RabbitMQ, used for message exchange.
- SECRET_KEY_BASE: The secret key for Wanda.
- CORS_ORIGIN: The origin URL from where API requests are allowed (pointing to web).
- ACCESS_TOKEN_ENC_SECRET: Secret key for encrypting access tokens.
- PORT: The port on which Wanda will run (4001 in this case).
- MIX_ENV: The environment in which Wanda will run (set to "demo" for the demo environment).

## Modify demo facts configuration

In the Wanda demo environment, configure fake facts by editing the [fake_facts configuration](https://github.com/trento-project/wanda/blob/main/priv/demo/fake_facts.yaml). Define or modify custom facts for different targets and checks.

### YAML Structure

The Configuration is saved in [fake_facts.yaml](https://github.com/trento-project/wanda/blob/main/priv/demo/fake_facts.yaml) file, which follows a specific structure with two main sections: `targets` and `facts`.

Example:

```yaml
targets:
target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4
target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc
facts:
check_1:
fact_name1:
target1: 2
target2: 3
```
### Targets
The targets section allows defining handles for targets' UUIDs, providing a reference that can be used through the configuration.
Format:
```yaml
targets:
<target_reference>: <target_id>
```
<target_reference>: A user-defined handle or reference for a target.
<target_id>: The UUID or identifier of the target.
Add as many new target entries as required:
```yaml
targets:
target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4
target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc
<target_reference>: <new_target_id>
```
### Facts:
The facts section allows specifying what fact value a target should return for a specific check.
The format for the facts section is as follows:
```yaml
facts:
<check_id>:
<fact_name>:
<target_reference>: <fact value>
<target_reference2>: <fact value>
```
- There can be as many <check_id> as needed.
- Each <check_id> there can be as many <fact_name> configured as needed.
- Each <fact_name> can be instrumented to have a specific <fact value> on a <target_reference>.
Example:
```yaml
targets:
target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4
target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc
target3: 3f16cb32-57fb-46cc-9bf1-cd8d72d7eb9a

facts:
.......existing facts..........
new_check_id:
new_fact_name:
target1: <fact value>
target2: <fact value>
target3: <fact value>
```
## FAQ
### What happens with unmapped targets, facts or checks?
Wanda will still evaluate and return a default fallback fact value "some fact value" for a check's execution. This means when a new check is added to wanda, changing the the configuration is optional.
### How to know what's the correct return value of a fact?
Every Fact Gatherer has specific return values. To get an overview of all gatherers, refer to [Wanda's gatherers guide](../gatherers.md).
Determining the correct return value of a fact requires inspecting the specific check itself.
Visit the [Checks Catalog](https://github.com/trento-project/wanda/blob/main/priv/catalog) to find out which gatherer is used for the specific check and which values are expected.
Loading

0 comments on commit 376870d

Please sign in to comment.