Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation update #176

Merged
merged 4 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions guides/configuration.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## Configuration

Amoc is configured through environment variables (uppercase with prefix ``AMOC_``).
Note that the environment variables are evaluated as Erlang code.
Note that by default, environment variables values are deserialized as Erlang terms. This behavior can be customized by providing an alternative parsing module in the `config_parser_mod` configuration parameter for the amoc application. It can be done using the [application:set_env/4](https://www.erlang.org/doc/man/application#set_env-4) interface or via a [config file](https://www.erlang.org/doc/man/config). The custom parsing module must implement the `amoc_config_env` behavior.

Amoc supports the following generic configuration parameters:

Expand All @@ -12,7 +12,7 @@ Amoc supports the following generic configuration parameters:
* ``api_port`` - a port for the amoc REST interfaces:
* default value - 4000
* example: `AMOC_API_PORT="4000"`

* ``interarrival`` - a delay (in ms, for each node in the cluster independently) between creating the processes
for two consecutive users:
* default value - 50 ms.
Expand Down Expand Up @@ -61,7 +61,7 @@ where
* **Default:** this field is mandatory

### `description`
* **Syntax:** A string describing how this variable is used, can be extracted by APIs to document the behaviour
* **Syntax:** A string describing how this variable is used, can be extracted by APIs to document the behavior
* **Example:** `description = "a description of this variable"`
* **Default:** this field is mandatory

Expand Down Expand Up @@ -91,17 +91,17 @@ An action to take when the value of this variable is updated. It is triggered at
- If it is set to `none`, all updates are allowed.
- If it is an `mfa`, the given function will be called on the old and new value.

## Reasonale
## Rationale

The reason why the `-required_variable(...)` is preferred over the usual behaviour
The reason why the `-required_variable(...)` is preferred over the usual behavior
callback is because the orchestration tools can easily extract the attributes even
without the compilation, while configuring via a callback, requires a successful
compilation of the module. As an example, a module:
```erlang
-module(example).
-include("some_unavailable_header.hrl").
-some_attr({"some", value}).
-some_attr([{another, "value"},
-some_attr([{another, "value"},
{yet, <<"another">>, "value"}]).
```
cannot be compiled without the ``some_unavailable_header.hrl`` file, but we still
Expand All @@ -115,9 +115,9 @@ error
{ok,[{attribute,1,file,{"example.erl",1}},
{attribute,1,module,example},
{error,{2,epp,{include,file,"some_unavailable_header.hrl"}}},
{attribute,3,some_attr,{"some",value}},
{attribute,3,some_attr,{"some",value}},
{attribute,4,some_attr,
[{another,"value"},{yet,<<"another">>,"value"}]},
[{another,"value"},{yet,<<"another">>,"value"}]},
{eof,6}]}
3> lists:flatten([Value || {attribute, _, some_attr, Value} <- AbstractForm]).
[{"some",value},
Expand Down
19 changes: 5 additions & 14 deletions src/amoc_config/amoc_config_env.erl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
%% @end
-module(amoc_config_env).

-export([get/1, get/2]).
-export([get/2]).

-define(DEFAULT_PARSER_MODULE, amoc_config_parser).

Expand All @@ -21,19 +21,8 @@
%% ------------------------------------------------------------------
%% API
%% ------------------------------------------------------------------
-spec get(amoc_config:name()) -> amoc_config:value().
get(Name) ->
get(Name, undefined).

-spec get(amoc_config:name(), amoc_config:value()) -> amoc_config:value().
get(Name, Default) when is_atom(Name) ->
get_os_env(Name, Default).

%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
-spec get_os_env(amoc_config:name(), amoc_config:value()) -> amoc_config:value().
get_os_env(Name, Default) ->
EnvName = os_env_name(Name),
Value = os:getenv(EnvName),
case parse_value(Value, Default) of
Expand All @@ -47,6 +36,9 @@ get_os_env(Name, Default) ->
Default
end.

%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
-spec os_env_name(amoc_config:name()) -> string().
os_env_name(Name) when is_atom(Name) ->
"AMOC_" ++ string:uppercase(erlang:atom_to_list(Name)).
Expand All @@ -55,8 +47,7 @@ os_env_name(Name) when is_atom(Name) ->
parse_value(false, Default) -> {ok, Default};
parse_value("", Default) -> {ok, Default};
parse_value(String, _) ->
App = application:get_application(?MODULE),
Mod = application:get_env(App, config_parser_mod, ?DEFAULT_PARSER_MODULE),
Mod = application:get_env(amoc, config_parser_mod, ?DEFAULT_PARSER_MODULE),
try Mod:parse_value(String) of
{ok, Value} -> {ok, Value};
{error, Error} -> {error, Error};
Expand Down
9 changes: 1 addition & 8 deletions src/amoc_config/amoc_config_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
merge_config/2,
override_config/2,
store_scenario_config/1,
create_amoc_config_ets/0,
find_all_vars/1]).
create_amoc_config_ets/0]).

-spec maybe_error(error_type(), [{error, reason()} | {ok, any()}]) ->
error() | {ok, [any()]}.
Expand Down Expand Up @@ -71,9 +70,3 @@ create_amoc_config_ets() ->
protected,
{keypos, #module_parameter.name},
{read_concurrency, true}]).

-spec find_all_vars(atom()) -> [any()].
find_all_vars(Name) ->
AllValues = [application:get_env(App, Name)
|| {App, _, _} <- application:loaded_applications()],
[Value || {ok, Value} <- AllValues].
23 changes: 14 additions & 9 deletions test/amoc_config_env_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,22 @@ end_per_suite(_) ->

init_per_testcase(valid_custom_parser_test, Config) ->
meck:new(?MOCK_MOD, [non_strict, no_link]),
App = application:get_application(amoc_config_env),
application:set_env(App, config_parser_mod, ?MOCK_MOD),
ct:pal("amoc_config_env module belongs to '~p' application", [App]),
set_config_parser_module(?MOCK_MOD),
ct:pal("AMOC_* OS env. variables:~n ~p",
[[AmocEnv || "AMOC_" ++ _ = AmocEnv <- os:getenv()]]),
Config;
init_per_testcase(invalid_custom_parser_test, Config) ->
App = application:get_application(amoc_config_env),
%% setting non-existing config parser module
application:set_env(App, config_parser_mod, invalid_parser_module),
set_config_parser_module(invalid_parser_module),
Config;
init_per_testcase(_, Config) ->
Config.

end_per_testcase(valid_custom_parser_test, _Config) ->
App = application:get_application(amoc_config_env),
application:unset_env(App, config_parser_mod),
unset_config_parser_module(),
meck:unload();
end_per_testcase(invalid_custom_parser_test, _Config) ->
App = application:get_application(amoc_config_env),
application:unset_env(App, config_parser_mod);
unset_config_parser_module();
end_per_testcase(_, _Config) ->
ok.
%%-----------------------------------------------------------------------------------
Expand Down Expand Up @@ -130,3 +125,13 @@ invalid_custom_parser_test(_) ->
?assertEqual(default_value, get_env(unset_var, default_value)),
?assertEqual(undefined, get_env(empty_var)),
?assertEqual(default_value, get_env(empty_var, default_value)).

%%-----------------------------------------------------------------------------------
%% helper functions
%%-----------------------------------------------------------------------------------

set_config_parser_module(Mod) ->
application:set_env(amoc, config_parser_mod, Mod).

unset_config_parser_module() ->
application:unset_env(amoc, config_parser_mod).
2 changes: 1 addition & 1 deletion test/amoc_config_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ env_name(Name) ->
"AMOC_" ++ string:uppercase(erlang:atom_to_list(Name)).

get_env(Name) ->
amoc_config_env:get(Name).
get_env(Name, undefined).

get_env(Name, Default) ->
amoc_config_env:get(Name, Default).
Expand Down